| Index: cc/trees/layer_tree_host_unittest_copyrequest.cc
|
| diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a7fad10921dc610059258572bd0a9214da6809b5
|
| --- /dev/null
|
| +++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
|
| @@ -0,0 +1,831 @@
|
| +// 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/output/copy_output_request.h"
|
| +#include "cc/output/copy_output_result.h"
|
| +#include "cc/test/fake_content_layer.h"
|
| +#include "cc/test/fake_content_layer_client.h"
|
| +#include "cc/test/fake_output_surface.h"
|
| +#include "cc/test/layer_tree_test.h"
|
| +#include "cc/trees/layer_tree_impl.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:
|
| + virtual void SetupTree() OVERRIDE {
|
| + root = FakeContentLayer::Create(&client_);
|
| + root->SetBounds(gfx::Size(20, 20));
|
| +
|
| + child = FakeContentLayer::Create(&client_);
|
| + child->SetBounds(gfx::Size(10, 10));
|
| + root->AddChild(child);
|
| +
|
| + layer_tree_host()->SetRootLayer(root);
|
| + LayerTreeHostCopyRequestTest::SetupTree();
|
| + }
|
| +
|
| + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
|
| +
|
| + virtual void DidCommitAndDrawFrame() OVERRIDE { WaitForCallback(); }
|
| +
|
| + void WaitForCallback() {
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::NextStep,
|
| + base::Unretained(this)));
|
| + }
|
| +
|
| + void NextStep() {
|
| + int frame = layer_tree_host()->source_frame_number();
|
| + switch (frame) {
|
| + case 1:
|
| + child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
|
| + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::
|
| + CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + EXPECT_EQ(0u, callbacks_.size());
|
| + break;
|
| + case 2:
|
| + if (callbacks_.size() < 1u) {
|
| + WaitForCallback();
|
| + return;
|
| + }
|
| + EXPECT_EQ(1u, callbacks_.size());
|
| + EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString());
|
| +
|
| + child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
|
| + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::
|
| + CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + root->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
|
| + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::
|
| + CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
|
| + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::
|
| + CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + EXPECT_EQ(1u, callbacks_.size());
|
| + break;
|
| + case 3:
|
| + if (callbacks_.size() < 4u) {
|
| + WaitForCallback();
|
| + return;
|
| + }
|
| + EXPECT_EQ(4u, callbacks_.size());
|
| + // The child was copied to a bitmap and passed back twice.
|
| + EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[1].ToString());
|
| + EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[2].ToString());
|
| + // The root was copied to a bitmap and passed back also.
|
| + EXPECT_EQ(gfx::Size(20, 20).ToString(), callbacks_[3].ToString());
|
| + EndTest();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
|
| + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
|
| + EXPECT_TRUE(result->HasBitmap());
|
| + scoped_ptr<SkBitmap> bitmap = result->TakeBitmap().Pass();
|
| + EXPECT_EQ(result->size().ToString(),
|
| + gfx::Size(bitmap->width(), bitmap->height()).ToString());
|
| + callbacks_.push_back(result->size());
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE { EXPECT_EQ(4u, callbacks_.size()); }
|
| +
|
| + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
|
| + OVERRIDE {
|
| + scoped_ptr<FakeOutputSurface> output_surface;
|
| + if (use_gl_renderer_) {
|
| + output_surface = FakeOutputSurface::Create3d().Pass();
|
| + } else {
|
| + output_surface = FakeOutputSurface::CreateSoftware(
|
| + make_scoped_ptr(new SoftwareOutputDevice)).Pass();
|
| + }
|
| + return output_surface.PassAs<OutputSurface>();
|
| + }
|
| +
|
| + bool use_gl_renderer_;
|
| + std::vector<gfx::Size> callbacks_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakeContentLayer> root;
|
| + scoped_refptr<FakeContentLayer> child;
|
| +};
|
| +
|
| +// Readback can't be done with a delegating renderer.
|
| +TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
|
| + GLRenderer_RunSingleThread) {
|
| + use_gl_renderer_ = true;
|
| + RunTest(false, false, false);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
|
| + GLRenderer_RunMultiThread_MainThreadPainting) {
|
| + use_gl_renderer_ = true;
|
| + RunTest(true, false, false);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
|
| + SoftwareRenderer_RunSingleThread) {
|
| + use_gl_renderer_ = false;
|
| + RunTest(false, false, false);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
|
| + SoftwareRenderer_RunMultiThread_MainThreadPainting) {
|
| + use_gl_renderer_ = false;
|
| + RunTest(true, false, false);
|
| +}
|
| +
|
| +class LayerTreeHostCopyRequestTestLayerDestroyed
|
| + : public LayerTreeHostCopyRequestTest {
|
| + protected:
|
| + virtual void SetupTree() OVERRIDE {
|
| + root_ = FakeContentLayer::Create(&client_);
|
| + root_->SetBounds(gfx::Size(20, 20));
|
| +
|
| + main_destroyed_ = FakeContentLayer::Create(&client_);
|
| + main_destroyed_->SetBounds(gfx::Size(15, 15));
|
| + root_->AddChild(main_destroyed_);
|
| +
|
| + impl_destroyed_ = FakeContentLayer::Create(&client_);
|
| + impl_destroyed_->SetBounds(gfx::Size(10, 10));
|
| + root_->AddChild(impl_destroyed_);
|
| +
|
| + layer_tree_host()->SetRootLayer(root_);
|
| + LayerTreeHostCopyRequestTest::SetupTree();
|
| + }
|
| +
|
| + virtual void BeginTest() OVERRIDE {
|
| + callback_count_ = 0;
|
| + PostSetNeedsCommitToMainThread();
|
| + }
|
| +
|
| + virtual void DidCommit() OVERRIDE {
|
| + int frame = layer_tree_host()->source_frame_number();
|
| + switch (frame) {
|
| + case 1:
|
| + main_destroyed_->RequestCopyOfOutput(
|
| + CopyOutputRequest::CreateBitmapRequest(base::Bind(
|
| + &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + impl_destroyed_->RequestCopyOfOutput(
|
| + CopyOutputRequest::CreateBitmapRequest(base::Bind(
|
| + &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + EXPECT_EQ(0, callback_count_);
|
| +
|
| + // Destroy the main thread layer right away.
|
| + main_destroyed_->RemoveFromParent();
|
| + main_destroyed_ = NULL;
|
| +
|
| + // 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()->SetViewportSize(gfx::Size());
|
| + 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_ = NULL;
|
| +
|
| + // 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(scoped_ptr<CopyOutputResult> result) {
|
| + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
|
| + EXPECT_TRUE(result->IsEmpty());
|
| + ++callback_count_;
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE {}
|
| +
|
| + int callback_count_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakeContentLayer> root_;
|
| + scoped_refptr<FakeContentLayer> main_destroyed_;
|
| + scoped_refptr<FakeContentLayer> impl_destroyed_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestLayerDestroyed);
|
| +
|
| +class LayerTreeHostCopyRequestTestInHiddenSubtree
|
| + : public LayerTreeHostCopyRequestTest {
|
| + protected:
|
| + virtual void SetupTree() OVERRIDE {
|
| + root_ = FakeContentLayer::Create(&client_);
|
| + root_->SetBounds(gfx::Size(20, 20));
|
| +
|
| + grand_parent_layer_ = FakeContentLayer::Create(&client_);
|
| + grand_parent_layer_->SetBounds(gfx::Size(15, 15));
|
| + root_->AddChild(grand_parent_layer_);
|
| +
|
| + // parent_layer_ owns a render surface.
|
| + parent_layer_ = FakeContentLayer::Create(&client_);
|
| + parent_layer_->SetBounds(gfx::Size(15, 15));
|
| + parent_layer_->SetForceRenderSurface(true);
|
| + grand_parent_layer_->AddChild(parent_layer_);
|
| +
|
| + copy_layer_ = FakeContentLayer::Create(&client_);
|
| + copy_layer_->SetBounds(gfx::Size(10, 10));
|
| + parent_layer_->AddChild(copy_layer_);
|
| +
|
| + layer_tree_host()->SetRootLayer(root_);
|
| + LayerTreeHostCopyRequestTest::SetupTree();
|
| + }
|
| +
|
| + void AddCopyRequest(Layer* layer) {
|
| + layer->RequestCopyOfOutput(
|
| + CopyOutputRequest::CreateBitmapRequest(base::Bind(
|
| + &LayerTreeHostCopyRequestTestInHiddenSubtree::CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + }
|
| +
|
| + virtual void BeginTest() OVERRIDE {
|
| + callback_count_ = 0;
|
| + PostSetNeedsCommitToMainThread();
|
| +
|
| + AddCopyRequest(copy_layer_.get());
|
| + }
|
| +
|
| + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
|
| + ++callback_count_;
|
| + EXPECT_TRUE(layer_tree_host()->proxy()->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;
|
| + }
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE {}
|
| +
|
| + int callback_count_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakeContentLayer> root_;
|
| + scoped_refptr<FakeContentLayer> grand_parent_layer_;
|
| + scoped_refptr<FakeContentLayer> parent_layer_;
|
| + scoped_refptr<FakeContentLayer> copy_layer_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
|
| + LayerTreeHostCopyRequestTestInHiddenSubtree);
|
| +
|
| +class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest
|
| + : public LayerTreeHostCopyRequestTest {
|
| + protected:
|
| + virtual void SetupTree() OVERRIDE {
|
| + root_ = FakeContentLayer::Create(&client_);
|
| + root_->SetBounds(gfx::Size(20, 20));
|
| +
|
| + grand_parent_layer_ = FakeContentLayer::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_ = FakeContentLayer::Create(&client_);
|
| + parent_layer_->SetBounds(gfx::Size(15, 15));
|
| + parent_layer_->SetForceRenderSurface(true);
|
| + grand_parent_layer_->AddChild(parent_layer_);
|
| +
|
| + copy_layer_ = FakeContentLayer::Create(&client_);
|
| + copy_layer_->SetBounds(gfx::Size(10, 10));
|
| + parent_layer_->AddChild(copy_layer_);
|
| +
|
| + layer_tree_host()->SetRootLayer(root_);
|
| + LayerTreeHostCopyRequestTest::SetupTree();
|
| + }
|
| +
|
| + virtual void BeginTest() OVERRIDE {
|
| + did_draw_ = false;
|
| + PostSetNeedsCommitToMainThread();
|
| +
|
| + copy_layer_->RequestCopyOfOutput(
|
| + CopyOutputRequest::CreateBitmapRequest(base::Bind(
|
| + &LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest::
|
| + CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + }
|
| +
|
| + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
|
| + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
|
| + EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString());
|
| + EndTest();
|
| + }
|
| +
|
| + virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
|
| + Renderer* renderer = host_impl->renderer();
|
| +
|
| + LayerImpl* root = host_impl->active_tree()->root_layer();
|
| + LayerImpl* grand_parent = root->children()[0];
|
| + LayerImpl* parent = grand_parent->children()[0];
|
| + LayerImpl* copy_layer = parent->children()[0];
|
| +
|
| + // |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_surface()->RenderPassId()));
|
| +
|
| + // |copy_layer| should have been rendered to a texture since it was needed
|
| + // for a copy request.
|
| + EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
|
| + copy_layer->render_surface()->RenderPassId()));
|
| +
|
| + did_draw_ = true;
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE { EXPECT_TRUE(did_draw_); }
|
| +
|
| + FakeContentLayerClient client_;
|
| + bool did_draw_;
|
| + scoped_refptr<FakeContentLayer> root_;
|
| + scoped_refptr<FakeContentLayer> grand_parent_layer_;
|
| + scoped_refptr<FakeContentLayer> parent_layer_;
|
| + scoped_refptr<FakeContentLayer> copy_layer_;
|
| +};
|
| +
|
| +// No output to copy for delegated renderers.
|
| +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
|
| + LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest);
|
| +
|
| +class LayerTreeHostCopyRequestTestClippedOut
|
| + : public LayerTreeHostCopyRequestTest {
|
| + protected:
|
| + virtual void SetupTree() OVERRIDE {
|
| + root_ = FakeContentLayer::Create(&client_);
|
| + root_->SetBounds(gfx::Size(20, 20));
|
| +
|
| + parent_layer_ = FakeContentLayer::Create(&client_);
|
| + parent_layer_->SetBounds(gfx::Size(15, 15));
|
| + parent_layer_->SetMasksToBounds(true);
|
| + root_->AddChild(parent_layer_);
|
| +
|
| + copy_layer_ = FakeContentLayer::Create(&client_);
|
| + copy_layer_->SetPosition(gfx::Point(15, 15));
|
| + copy_layer_->SetBounds(gfx::Size(10, 10));
|
| + parent_layer_->AddChild(copy_layer_);
|
| +
|
| + layer_tree_host()->SetRootLayer(root_);
|
| + LayerTreeHostCopyRequestTest::SetupTree();
|
| + }
|
| +
|
| + virtual void BeginTest() OVERRIDE {
|
| + PostSetNeedsCommitToMainThread();
|
| +
|
| + copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
|
| + base::Bind(&LayerTreeHostCopyRequestTestClippedOut::CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + }
|
| +
|
| + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
|
| + // We should still get a callback with no output if the copy requested layer
|
| + // was completely clipped away.
|
| + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
|
| + EXPECT_EQ(gfx::Size().ToString(), result->size().ToString());
|
| + EndTest();
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE {}
|
| +
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakeContentLayer> root_;
|
| + scoped_refptr<FakeContentLayer> parent_layer_;
|
| + scoped_refptr<FakeContentLayer> copy_layer_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
|
| + LayerTreeHostCopyRequestTestClippedOut);
|
| +
|
| +class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw
|
| + : public LayerTreeHostCopyRequestTest {
|
| + protected:
|
| + virtual void SetupTree() OVERRIDE {
|
| + root_ = FakeContentLayer::Create(&client_);
|
| + root_->SetBounds(gfx::Size(20, 20));
|
| +
|
| + copy_layer_ = FakeContentLayer::Create(&client_);
|
| + copy_layer_->SetBounds(gfx::Size(10, 10));
|
| + root_->AddChild(copy_layer_);
|
| +
|
| + layer_tree_host()->SetRootLayer(root_);
|
| + LayerTreeHostCopyRequestTest::SetupTree();
|
| + }
|
| +
|
| + void AddCopyRequest(Layer* layer) {
|
| + layer->RequestCopyOfOutput(
|
| + CopyOutputRequest::CreateBitmapRequest(base::Bind(
|
| + &LayerTreeHostTestAsyncTwoReadbacksWithoutDraw::CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + }
|
| +
|
| + virtual void BeginTest() OVERRIDE {
|
| + saw_copy_request_ = false;
|
| + callback_count_ = 0;
|
| + PostSetNeedsCommitToMainThread();
|
| +
|
| + // Prevent drawing.
|
| + layer_tree_host()->SetViewportSize(gfx::Size(0, 0));
|
| +
|
| + AddCopyRequest(copy_layer_.get());
|
| + }
|
| +
|
| + virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
|
| + if (impl->active_tree()->source_frame_number() == 0) {
|
| + LayerImpl* root = impl->active_tree()->root_layer();
|
| + EXPECT_TRUE(root->children()[0]->HasCopyRequest());
|
| + saw_copy_request_ = true;
|
| + }
|
| + }
|
| +
|
| + virtual void DidCommit() OVERRIDE {
|
| + if (layer_tree_host()->source_frame_number() == 1) {
|
| + // Allow drawing.
|
| + layer_tree_host()->SetViewportSize(gfx::Size(root_->bounds()));
|
| +
|
| + AddCopyRequest(copy_layer_.get());
|
| + }
|
| + }
|
| +
|
| + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
|
| + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
|
| + EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString());
|
| + ++callback_count_;
|
| +
|
| + if (callback_count_ == 2)
|
| + EndTest();
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE { EXPECT_TRUE(saw_copy_request_); }
|
| +
|
| + bool saw_copy_request_;
|
| + int callback_count_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakeContentLayer> root_;
|
| + scoped_refptr<FakeContentLayer> copy_layer_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
|
| + LayerTreeHostTestAsyncTwoReadbacksWithoutDraw);
|
| +
|
| +class LayerTreeHostCopyRequestTestLostOutputSurface
|
| + : public LayerTreeHostCopyRequestTest {
|
| + protected:
|
| + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
|
| + OVERRIDE {
|
| + if (!first_context_provider_.get()) {
|
| + first_context_provider_ = TestContextProvider::Create();
|
| + return FakeOutputSurface::Create3d(first_context_provider_)
|
| + .PassAs<OutputSurface>();
|
| + }
|
| +
|
| + EXPECT_FALSE(second_context_provider_.get());
|
| + second_context_provider_ = TestContextProvider::Create();
|
| + return FakeOutputSurface::Create3d(second_context_provider_)
|
| + .PassAs<OutputSurface>();
|
| + }
|
| +
|
| + virtual void SetupTree() OVERRIDE {
|
| + root_ = FakeContentLayer::Create(&client_);
|
| + root_->SetBounds(gfx::Size(20, 20));
|
| +
|
| + copy_layer_ = FakeContentLayer::Create(&client_);
|
| + copy_layer_->SetBounds(gfx::Size(10, 10));
|
| + root_->AddChild(copy_layer_);
|
| +
|
| + layer_tree_host()->SetRootLayer(root_);
|
| + LayerTreeHostCopyRequestTest::SetupTree();
|
| + }
|
| +
|
| + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
|
| +
|
| + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
|
| + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
|
| + EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString());
|
| + EXPECT_TRUE(result->HasTexture());
|
| +
|
| + // Save the result for later.
|
| + EXPECT_FALSE(result_);
|
| + result_ = result.Pass();
|
| +
|
| + // Post a commit to lose the output surface.
|
| + layer_tree_host()->SetNeedsCommit();
|
| + }
|
| +
|
| + virtual void DidCommitAndDrawFrame() OVERRIDE {
|
| + switch (layer_tree_host()->source_frame_number()) {
|
| + case 1:
|
| + // The layers have been pushed to the impl side. The layer textures have
|
| + // been allocated.
|
| +
|
| + // Request a copy of the layer. This will use another texture.
|
| + copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateRequest(
|
| + base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
|
| + CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + break;
|
| + case 4:
|
| + // With SingleThreadProxy it takes two commits to finally swap after a
|
| + // context loss.
|
| + case 5:
|
| + // Now destroy the CopyOutputResult, releasing the texture inside back
|
| + // to the compositor.
|
| + EXPECT_TRUE(result_);
|
| + result_.reset();
|
| +
|
| + // Check that it is released.
|
| + ImplThreadTaskRunner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
|
| + CheckNumTextures,
|
| + base::Unretained(this),
|
| + num_textures_after_loss_ - 1));
|
| + break;
|
| + }
|
| + }
|
| +
|
| + virtual void SwapBuffersOnThread(LayerTreeHostImpl* impl,
|
| + bool result) OVERRIDE {
|
| + switch (impl->active_tree()->source_frame_number()) {
|
| + case 0:
|
| + // The layers have been drawn, so their textures have been allocated.
|
| + EXPECT_FALSE(result_);
|
| + num_textures_without_readback_ =
|
| + first_context_provider_->TestContext3d()->NumTextures();
|
| + break;
|
| + case 1:
|
| + // We did a readback, so there will be a readback texture around now.
|
| + EXPECT_LT(num_textures_without_readback_,
|
| + first_context_provider_->TestContext3d()->NumTextures());
|
| + break;
|
| + case 2:
|
| + // The readback texture is collected.
|
| + EXPECT_TRUE(result_);
|
| +
|
| + // Lose the output surface.
|
| + first_context_provider_->TestContext3d()->loseContextCHROMIUM(
|
| + GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
|
| + break;
|
| + case 3:
|
| + // With SingleThreadProxy it takes two commits to finally swap after a
|
| + // context loss.
|
| + case 4:
|
| + // The output surface has been recreated.
|
| + EXPECT_TRUE(second_context_provider_.get());
|
| +
|
| + num_textures_after_loss_ =
|
| + first_context_provider_->TestContext3d()->NumTextures();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void CheckNumTextures(size_t expected_num_textures) {
|
| + EXPECT_EQ(expected_num_textures,
|
| + first_context_provider_->TestContext3d()->NumTextures());
|
| + EndTest();
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE {}
|
| +
|
| + scoped_refptr<TestContextProvider> first_context_provider_;
|
| + scoped_refptr<TestContextProvider> second_context_provider_;
|
| + size_t num_textures_without_readback_;
|
| + size_t num_textures_after_loss_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakeContentLayer> root_;
|
| + scoped_refptr<FakeContentLayer> copy_layer_;
|
| + scoped_ptr<CopyOutputResult> result_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
|
| + LayerTreeHostCopyRequestTestLostOutputSurface);
|
| +
|
| +class LayerTreeHostCopyRequestTestCountTextures
|
| + : public LayerTreeHostCopyRequestTest {
|
| + protected:
|
| + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
|
| + OVERRIDE {
|
| + context_provider_ = TestContextProvider::Create();
|
| + return FakeOutputSurface::Create3d(context_provider_)
|
| + .PassAs<OutputSurface>();
|
| + }
|
| +
|
| + virtual void SetupTree() OVERRIDE {
|
| + root_ = FakeContentLayer::Create(&client_);
|
| + root_->SetBounds(gfx::Size(20, 20));
|
| +
|
| + copy_layer_ = FakeContentLayer::Create(&client_);
|
| + copy_layer_->SetBounds(gfx::Size(10, 10));
|
| + root_->AddChild(copy_layer_);
|
| +
|
| + layer_tree_host()->SetRootLayer(root_);
|
| + LayerTreeHostCopyRequestTest::SetupTree();
|
| + }
|
| +
|
| + virtual void BeginTest() OVERRIDE {
|
| + num_textures_without_readback_ = 0;
|
| + num_textures_with_readback_ = 0;
|
| + waited_sync_point_after_readback_ = 0;
|
| + PostSetNeedsCommitToMainThread();
|
| + }
|
| +
|
| + virtual void RequestCopy(Layer* layer) = 0;
|
| +
|
| + virtual void DidCommitAndDrawFrame() OVERRIDE {
|
| + switch (layer_tree_host()->source_frame_number()) {
|
| + case 1:
|
| + // The layers have been pushed to the impl side. The layer textures have
|
| + // been allocated.
|
| + RequestCopy(copy_layer_.get());
|
| + break;
|
| + }
|
| + }
|
| +
|
| + virtual void SwapBuffersOnThread(LayerTreeHostImpl* impl,
|
| + bool result) OVERRIDE {
|
| + switch (impl->active_tree()->source_frame_number()) {
|
| + case 0:
|
| + // The layers have been drawn, so their textures have been allocated.
|
| + num_textures_without_readback_ =
|
| + context_provider_->TestContext3d()->NumTextures();
|
| + break;
|
| + case 1:
|
| + // We did a readback, so there will be a readback texture around now.
|
| + num_textures_with_readback_ =
|
| + context_provider_->TestContext3d()->NumTextures();
|
| + waited_sync_point_after_readback_ =
|
| + context_provider_->TestContext3d()->last_waited_sync_point();
|
| +
|
| + MainThreadTaskRunner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&LayerTreeHostCopyRequestTestCountTextures::DoEndTest,
|
| + base::Unretained(this)));
|
| + break;
|
| + }
|
| + }
|
| +
|
| + virtual void DoEndTest() { EndTest(); }
|
| +
|
| + scoped_refptr<TestContextProvider> context_provider_;
|
| + size_t num_textures_without_readback_;
|
| + size_t num_textures_with_readback_;
|
| + unsigned waited_sync_point_after_readback_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakeContentLayer> root_;
|
| + scoped_refptr<FakeContentLayer> copy_layer_;
|
| +};
|
| +
|
| +class LayerTreeHostCopyRequestTestCreatesTexture
|
| + : public LayerTreeHostCopyRequestTestCountTextures {
|
| + protected:
|
| + virtual void RequestCopy(Layer* layer) OVERRIDE {
|
| + // Request a normal texture copy. This should create a new texture.
|
| + copy_layer_->RequestCopyOfOutput(
|
| + CopyOutputRequest::CreateRequest(base::Bind(
|
| + &LayerTreeHostCopyRequestTestCreatesTexture::CopyOutputCallback,
|
| + base::Unretained(this))));
|
| + }
|
| +
|
| + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
|
| + EXPECT_FALSE(result->IsEmpty());
|
| + EXPECT_TRUE(result->HasTexture());
|
| +
|
| + TextureMailbox mailbox;
|
| + scoped_ptr<SingleReleaseCallback> release;
|
| + result->TakeTexture(&mailbox, &release);
|
| + EXPECT_TRUE(release);
|
| +
|
| + release->Run(0, false);
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE {
|
| + // No sync point was needed.
|
| + EXPECT_EQ(0u, waited_sync_point_after_readback_);
|
| + // Except the copy to have made another texture.
|
| + EXPECT_EQ(num_textures_without_readback_ + 1, num_textures_with_readback_);
|
| + }
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
|
| + LayerTreeHostCopyRequestTestCreatesTexture);
|
| +
|
| +class LayerTreeHostCopyRequestTestProvideTexture
|
| + : public LayerTreeHostCopyRequestTestCountTextures {
|
| + protected:
|
| + virtual void BeginTest() OVERRIDE {
|
| + external_context_provider_ = TestContextProvider::Create();
|
| + EXPECT_TRUE(external_context_provider_->BindToCurrentThread());
|
| + LayerTreeHostCopyRequestTestCountTextures::BeginTest();
|
| + }
|
| +
|
| + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
|
| + EXPECT_FALSE(result->IsEmpty());
|
| + EXPECT_TRUE(result->HasTexture());
|
| +
|
| + TextureMailbox mailbox;
|
| + scoped_ptr<SingleReleaseCallback> release;
|
| + result->TakeTexture(&mailbox, &release);
|
| + EXPECT_FALSE(release);
|
| + }
|
| +
|
| + virtual void RequestCopy(Layer* layer) OVERRIDE {
|
| + // Request a copy to a provided texture. This should not create a new
|
| + // texture.
|
| + scoped_ptr<CopyOutputRequest> request =
|
| + CopyOutputRequest::CreateRequest(base::Bind(
|
| + &LayerTreeHostCopyRequestTestProvideTexture::CopyOutputCallback,
|
| + base::Unretained(this)));
|
| +
|
| + gpu::Mailbox mailbox;
|
| + external_context_provider_->Context3d()->genMailboxCHROMIUM(mailbox.name);
|
| + sync_point_ = external_context_provider_->Context3d()->insertSyncPoint();
|
| + request->SetTextureMailbox(TextureMailbox(mailbox, sync_point_));
|
| + EXPECT_TRUE(request->has_texture_mailbox());
|
| +
|
| + copy_layer_->RequestCopyOfOutput(request.Pass());
|
| + }
|
| +
|
| + virtual void AfterTest() OVERRIDE {
|
| + // Expect the compositor to have waited for the sync point in the provided
|
| + // TextureMailbox.
|
| + EXPECT_EQ(sync_point_, waited_sync_point_after_readback_);
|
| + // Except the copy to have *not* made another texture.
|
| + EXPECT_EQ(num_textures_without_readback_, num_textures_with_readback_);
|
| + }
|
| +
|
| + scoped_refptr<TestContextProvider> external_context_provider_;
|
| + unsigned sync_point_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
|
| + LayerTreeHostCopyRequestTestProvideTexture);
|
| +
|
| +} // namespace
|
| +} // namespace cc
|
|
|