diff options
Diffstat (limited to 'cc/layer_tree_host_unittest_context.cc')
-rw-r--r-- | cc/layer_tree_host_unittest_context.cc | 791 |
1 files changed, 791 insertions, 0 deletions
diff --git a/cc/layer_tree_host_unittest_context.cc b/cc/layer_tree_host_unittest_context.cc new file mode 100644 index 0000000..89846f4 --- /dev/null +++ b/cc/layer_tree_host_unittest_context.cc @@ -0,0 +1,791 @@ +// Copyright 2012 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/layer_tree_host.h" + +#include "base/basictypes.h" +#include "cc/content_layer.h" +#include "cc/delegated_renderer_layer.h" +#include "cc/delegated_renderer_layer_impl.h" +#include "cc/heads_up_display_layer.h" +#include "cc/io_surface_layer.h" +#include "cc/layer_impl.h" +#include "cc/layer_tree_host_impl.h" +#include "cc/layer_tree_impl.h" +#include "cc/scrollbar_layer.h" +#include "cc/single_thread_proxy.h" +#include "cc/test/fake_content_layer.h" +#include "cc/test/fake_content_layer_client.h" +#include "cc/test/fake_content_layer_impl.h" +#include "cc/test/fake_output_surface.h" +#include "cc/test/fake_scrollbar_theme_painter.h" +#include "cc/test/fake_video_frame.h" +#include "cc/test/fake_video_frame_provider.h" +#include "cc/test/fake_web_graphics_context_3d.h" +#include "cc/test/fake_web_scrollbar.h" +#include "cc/test/fake_web_scrollbar_theme_geometry.h" +#include "cc/test/layer_tree_test_common.h" +#include "cc/test/render_pass_test_common.h" +#include "cc/texture_layer.h" +#include "cc/video_layer.h" +#include "cc/video_layer_impl.h" +#include "media/base/media.h" + +using media::VideoFrame; +using WebKit::WebGraphicsContext3D; + +namespace cc { +namespace { + +// These tests deal with losing the 3d graphics context. +class LayerTreeHostContextTest : public ThreadedTest { + public: + LayerTreeHostContextTest() + : ThreadedTest(), + context3d_(NULL), + times_to_fail_create_(0), + times_to_create_and_lose_(0), + times_to_lose_during_commit_(0), + times_to_repeat_loss_(0), + times_to_fail_recreate_(0) { + media::InitializeMediaLibraryForTesting(); + } + + void LoseContext() { + context3d_->loseContextCHROMIUM(); + context3d_ = NULL; + } + + virtual scoped_ptr<FakeWebGraphicsContext3D> CreateContext3d() { + return FakeWebGraphicsContext3D::Create(); + } + + virtual scoped_ptr<OutputSurface> createOutputSurface() OVERRIDE { + if (times_to_fail_create_) { + --times_to_fail_create_; + return scoped_ptr<OutputSurface>(); + } + + scoped_ptr<FakeWebGraphicsContext3D> context3d = CreateContext3d(); + context3d_ = context3d.get(); + + if (times_to_create_and_lose_) { + --times_to_create_and_lose_; + // Make the context get lost during reinitialization. + // The number of times MakeCurrent succeeds is not important, and + // can be changed if needed to make this pass with future changes. + context3d_->set_times_make_current_succeeds(2); + } + + return FakeOutputSurface::Create3d( + context3d.PassAs<WebGraphicsContext3D>()).PassAs<OutputSurface>(); + } + + virtual void commitCompleteOnThread(LayerTreeHostImpl *host_impl) OVERRIDE { + if (!times_to_lose_during_commit_) + return; + --times_to_lose_during_commit_; + LoseContext(); + + times_to_create_and_lose_ = times_to_repeat_loss_; + times_to_repeat_loss_ = 0; + times_to_fail_create_ = times_to_fail_recreate_; + times_to_fail_recreate_ = 0; + } + + protected: + FakeWebGraphicsContext3D* context3d_; + int times_to_fail_create_; + int times_to_create_and_lose_; + int times_to_lose_during_commit_; + int times_to_repeat_loss_; + int times_to_fail_recreate_; +}; + +class LayerTreeHostContextTestLostContextSucceeds : + public LayerTreeHostContextTest { + public: + LayerTreeHostContextTestLostContextSucceeds() + : LayerTreeHostContextTest(), + test_case_(0), + num_losses_(0) { + } + + virtual void beginTest() OVERRIDE { + postSetNeedsCommitToMainThread(); + } + + virtual void didRecreateOutputSurface(bool succeeded) OVERRIDE { + EXPECT_TRUE(succeeded); + ++num_losses_; + } + + virtual void afterTest() OVERRIDE { + EXPECT_EQ(3, test_case_); + EXPECT_EQ(3, num_losses_); + } + + bool SourceFrameHasContextLoss(int source_frame) const { + return source_frame % 2 == 1; + } + + virtual void didCommitAndDrawFrame() OVERRIDE { + // If the last frame had a context loss, then we'll commit again to + // recover. + if (SourceFrameHasContextLoss(m_layerTreeHost->commitNumber()) - 1) + return; + + if (NextTestCase()) + m_layerTreeHost->setNeedsCommit(); + else + endTest(); + } + + bool NextTestCase() { + static const TestCase kTests[] = { + // Losing the context and failing to recreate it (or losing it again + // immediately) a small number of times should succeed. + { 1, // times_to_lose_during_commit + 0, // times_to_repeat_loss + 0, // times_to_fail_recreate + }, + { 1, + 3, // times_to_repeat_loss + 0, // times_to_fail_recreate + }, + { 1, + 0, // times_to_repeat_loss + 3, // times_to_fail_recreate + }, + }; + + if (test_case_ >= arraysize(kTests)) + return false; + + times_to_lose_during_commit_ = + kTests[test_case_].times_to_lose_during_commit; + times_to_repeat_loss_ = kTests[test_case_].times_to_repeat_loss; + times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate; + ++test_case_; + return true; + } + + struct TestCase { + int times_to_lose_during_commit; + int times_to_repeat_loss; + int times_to_fail_recreate; + }; + + private: + size_t test_case_; + int num_losses_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds) + +class LayerTreeHostContextTestLostContextSucceedsWithContent : + public LayerTreeHostContextTestLostContextSucceeds { + public: + + LayerTreeHostContextTestLostContextSucceedsWithContent() + : LayerTreeHostContextTestLostContextSucceeds() { + } + + virtual void setupTree() OVERRIDE { + scoped_refptr<Layer> root_ = Layer::create(); + root_->setBounds(gfx::Size(10, 10)); + root_->setAnchorPoint(gfx::PointF()); + root_->setIsDrawable(true); + + scoped_refptr<FakeContentLayer> content_ = + FakeContentLayer::Create(&client_); + content_->setBounds(gfx::Size(10, 10)); + content_->setAnchorPoint(gfx::PointF()); + content_->setIsDrawable(true); + if (use_surface_) + content_->setForceRenderSurface(true); + root_->addChild(content_); + + m_layerTreeHost->setRootLayer(root_); + LayerTreeHostContextTest::setupTree(); + } + + virtual void drawLayersOnThread(LayerTreeHostImpl* host_impl) { + FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>( + host_impl->rootLayer()->children()[0]); + // Even though the context was lost, we should have a resource. The + // FakeWebGraphicsContext3D ensures that this resource is created with + // the active context. + EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0)); + } + + protected: + bool use_surface_; + FakeContentLayerClient client_; + scoped_refptr<Layer> root_; + scoped_refptr<ContentLayer> content_; +}; + +TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, + NoSurface_SingleThread) { + use_surface_ = false; + runTest(false); +} + +TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, + NoSurface_MultiThread) { + use_surface_ = false; + runTest(true); +} + +TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, + WithSurface_SingleThread) { + use_surface_ = true; + runTest(false); +} + +TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, + WithSurface_MultiThread) { + use_surface_ = true; + runTest(true); +} + +class LayerTreeHostContextTestLostContextFails : + public LayerTreeHostContextTest { + public: + LayerTreeHostContextTestLostContextFails() + : LayerTreeHostContextTest(), + num_commits_(0) { + times_to_lose_during_commit_ = 1; + } + + virtual void beginTest() OVERRIDE { + postSetNeedsCommitToMainThread(); + } + + virtual void didRecreateOutputSurface(bool succeeded) OVERRIDE { + EXPECT_FALSE(succeeded); + endTest(); + } + + virtual void commitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + LayerTreeHostContextTest::commitCompleteOnThread(host_impl); + + ++num_commits_; + if (num_commits_ == 1) { + // When the context is ok, we should have these things. + EXPECT_TRUE(host_impl->outputSurface()); + EXPECT_TRUE(host_impl->renderer()); + EXPECT_TRUE(host_impl->resourceProvider()); + return; + } + + // When context recreation fails we shouldn't be left with any of them. + EXPECT_FALSE(host_impl->outputSurface()); + EXPECT_FALSE(host_impl->renderer()); + EXPECT_FALSE(host_impl->resourceProvider()); + } + + virtual void afterTest() OVERRIDE {} + + private: + int num_commits_; +}; + +TEST_F(LayerTreeHostContextTestLostContextFails, RepeatLoss100_SingleThread) { + times_to_repeat_loss_ = 100; + times_to_fail_recreate_ = 0; + runTest(false); +} + +TEST_F(LayerTreeHostContextTestLostContextFails, RepeatLoss100_MultiThread) { + times_to_repeat_loss_ = 100; + times_to_fail_recreate_ = 0; + runTest(true); +} + +TEST_F(LayerTreeHostContextTestLostContextFails, FailRecreate100_SingleThread) { + times_to_repeat_loss_ = 0; + times_to_fail_recreate_ = 100; + runTest(false); +} + +TEST_F(LayerTreeHostContextTestLostContextFails, FailRecreate100_MultiThread) { + times_to_repeat_loss_ = 0; + times_to_fail_recreate_ = 100; + runTest(true); +} + +class LayerTreeHostContextTestFinishAllRenderingAfterLoss : + public LayerTreeHostContextTest { + public: + virtual void beginTest() OVERRIDE { + // Lose the context until the compositor gives up on it. + times_to_lose_during_commit_ = 1; + times_to_repeat_loss_ = 10; + postSetNeedsCommitToMainThread(); + } + + virtual void didRecreateOutputSurface(bool succeeded) OVERRIDE { + EXPECT_FALSE(succeeded); + m_layerTreeHost->finishAllRendering(); + endTest(); + } + + virtual void afterTest() OVERRIDE {} +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostContextTestFinishAllRenderingAfterLoss) + +class LayerTreeHostContextTestLostContextAndEvictTextures : + public LayerTreeHostContextTest { + public: + LayerTreeHostContextTestLostContextAndEvictTextures() + : LayerTreeHostContextTest(), + layer_(FakeContentLayer::Create(&client_)), + impl_host_(0), + num_commits_(0) { + } + + virtual void setupTree() OVERRIDE { + layer_->setBounds(gfx::Size(10, 20)); + m_layerTreeHost->setRootLayer(layer_); + LayerTreeHostContextTest::setupTree(); + } + + virtual void beginTest() OVERRIDE { + postSetNeedsCommitToMainThread(); + } + + void PostEvictTextures() { + if (implThread()) { + implThread()->postTask( + base::Bind( + &LayerTreeHostContextTestLostContextAndEvictTextures:: + EvictTexturesOnImplThread, + base::Unretained(this))); + } else { + DebugScopedSetImplThread impl(proxy()); + EvictTexturesOnImplThread(); + } + } + + void EvictTexturesOnImplThread() { + impl_host_->enforceManagedMemoryPolicy(ManagedMemoryPolicy(0)); + if (lose_after_evict_) + LoseContext(); + } + + virtual void didCommitAndDrawFrame() OVERRIDE { + if (num_commits_ > 1) + return; + EXPECT_TRUE(layer_->HaveBackingAt(0, 0)); + PostEvictTextures(); + } + + virtual void commitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE { + if (num_commits_ > 1) + return; + ++num_commits_; + if (!lose_after_evict_) + LoseContext(); + impl_host_ = impl; + } + + virtual void didRecreateOutputSurface(bool succeeded) OVERRIDE { + EXPECT_TRUE(succeeded); + endTest(); + } + + virtual void afterTest() OVERRIDE {} + + protected: + bool lose_after_evict_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> layer_; + LayerTreeHostImpl* impl_host_; + int num_commits_; +}; + +TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, + LoseAfterEvict_SingleThread) { + lose_after_evict_ = true; + runTest(false); +} + +TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, + LoseAfterEvict_MultiThread) { + lose_after_evict_ = true; + runTest(true); +} + +TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, + LoseBeforeEvict_SingleThread) { + lose_after_evict_ = false; + runTest(false); +} + +TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, + LoseBeforeEvict_MultiThread) { + lose_after_evict_ = false; + runTest(true); +} + +class LayerTreeHostContextTestLostContextWhileUpdatingResources : + public LayerTreeHostContextTest { + public: + LayerTreeHostContextTestLostContextWhileUpdatingResources() + : parent_(FakeContentLayer::Create(&client_)), + num_children_(50), + times_to_lose_on_end_query_(3) { + } + + virtual scoped_ptr<FakeWebGraphicsContext3D> CreateContext3d() { + scoped_ptr<FakeWebGraphicsContext3D> context = + LayerTreeHostContextTest::CreateContext3d(); + if (times_to_lose_on_end_query_) { + --times_to_lose_on_end_query_; + context->set_times_end_query_succeeds(5); + } + return context.Pass(); + } + + virtual void setupTree() { + parent_->setBounds(gfx::Size(num_children_, 1)); + + for (int i = 0; i < num_children_; i++) { + scoped_refptr<FakeContentLayer> child = + FakeContentLayer::Create(&client_); + child->setPosition(gfx::PointF(i, 0.f)); + child->setBounds(gfx::Size(1, 1)); + parent_->addChild(child); + } + + m_layerTreeHost->setRootLayer(parent_); + LayerTreeHostContextTest::setupTree(); + } + + virtual void beginTest() { + postSetNeedsCommitToMainThread(); + } + + virtual void commitCompleteOnThread(LayerTreeHostImpl* impl) { + endTest(); + } + + virtual void didRecreateOutputSurface(bool succeeded) OVERRIDE { + EXPECT_TRUE(succeeded); + } + + virtual void afterTest() { + EXPECT_EQ(0, times_to_lose_on_end_query_); + } + + private: + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> parent_; + int num_children_; + int times_to_lose_on_end_query_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostContextTestLostContextWhileUpdatingResources) + +class LayerTreeHostContextTestLayersNotified : + public LayerTreeHostContextTest { + public: + LayerTreeHostContextTestLayersNotified() + : LayerTreeHostContextTest(), + num_commits_(0) { + } + + virtual void setupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + child_ = FakeContentLayer::Create(&client_); + grandchild_ = FakeContentLayer::Create(&client_); + + root_->addChild(child_); + child_->addChild(grandchild_); + + m_layerTreeHost->setRootLayer(root_); + LayerTreeHostContextTest::setupTree(); + } + + virtual void beginTest() OVERRIDE { + postSetNeedsCommitToMainThread(); + } + + virtual void commitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>( + host_impl->rootLayer()); + FakeContentLayerImpl* child = static_cast<FakeContentLayerImpl*>( + root->children()[0]); + FakeContentLayerImpl* grandchild = static_cast<FakeContentLayerImpl*>( + child->children()[0]); + + ++num_commits_; + switch (num_commits_) { + case 1: + EXPECT_EQ(0u, root->lost_output_surface_count()); + EXPECT_EQ(0u, child->lost_output_surface_count()); + EXPECT_EQ(0u, grandchild->lost_output_surface_count()); + // Lose the context and struggle to recreate it. + LoseContext(); + times_to_fail_create_ = 1; + break; + case 2: + EXPECT_EQ(1u, root->lost_output_surface_count()); + EXPECT_EQ(1u, child->lost_output_surface_count()); + EXPECT_EQ(1u, grandchild->lost_output_surface_count()); + // Lose the context and again during recreate. + LoseContext(); + times_to_create_and_lose_ = 1; + break; + case 3: + EXPECT_EQ(3u, root->lost_output_surface_count()); + EXPECT_EQ(3u, child->lost_output_surface_count()); + EXPECT_EQ(3u, grandchild->lost_output_surface_count()); + endTest(); + break; + default: + NOTREACHED(); + } + } + + virtual void afterTest() OVERRIDE {} + + private: + int num_commits_; + + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> child_; + scoped_refptr<FakeContentLayer> grandchild_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified) + +class LayerTreeHostContextTestDontUseLostResources : + public LayerTreeHostContextTest { + public: + virtual void setupTree() OVERRIDE { + context3d_->set_have_extension_io_surface(true); + context3d_->set_have_extension_egl_image(true); + + scoped_refptr<Layer> root_ = Layer::create(); + root_->setBounds(gfx::Size(10, 10)); + root_->setAnchorPoint(gfx::PointF()); + root_->setIsDrawable(true); + + scoped_refptr<DelegatedRendererLayer> delegated_ = + DelegatedRendererLayer::create(); + delegated_->setBounds(gfx::Size(10, 10)); + delegated_->setAnchorPoint(gfx::PointF()); + delegated_->setIsDrawable(true); + root_->addChild(delegated_); + + scoped_refptr<ContentLayer> content_ = ContentLayer::create(&client_); + content_->setBounds(gfx::Size(10, 10)); + content_->setAnchorPoint(gfx::PointF()); + content_->setIsDrawable(true); + root_->addChild(content_); + + scoped_refptr<TextureLayer> texture_ = TextureLayer::create(NULL); + texture_->setBounds(gfx::Size(10, 10)); + texture_->setAnchorPoint(gfx::PointF()); + texture_->setTextureId(FakeWebGraphicsContext3D::kExternalTextureId); + texture_->setIsDrawable(true); + root_->addChild(texture_); + + scoped_refptr<ContentLayer> mask_ = ContentLayer::create(&client_); + mask_->setBounds(gfx::Size(10, 10)); + mask_->setAnchorPoint(gfx::PointF()); + + scoped_refptr<ContentLayer> content_with_mask_ = + ContentLayer::create(&client_); + content_with_mask_->setBounds(gfx::Size(10, 10)); + content_with_mask_->setAnchorPoint(gfx::PointF()); + content_with_mask_->setIsDrawable(true); + content_with_mask_->setMaskLayer(mask_.get()); + root_->addChild(content_with_mask_); + + VideoLayerImpl::FrameUnwrapper unwrapper = + base::Bind(FakeVideoFrame::ToVideoFrame); + + scoped_refptr<VideoLayer> video_color_ = VideoLayer::create( + &color_frame_provider_, unwrapper); + video_color_->setBounds(gfx::Size(10, 10)); + video_color_->setAnchorPoint(gfx::PointF()); + video_color_->setIsDrawable(true); + root_->addChild(video_color_); + + scoped_refptr<VideoLayer> video_hw_ = VideoLayer::create( + &hw_frame_provider_, unwrapper); + video_hw_->setBounds(gfx::Size(10, 10)); + video_hw_->setAnchorPoint(gfx::PointF()); + video_hw_->setIsDrawable(true); + root_->addChild(video_hw_); + + scoped_refptr<VideoLayer> video_scaled_hw_ = VideoLayer::create( + &scaled_hw_frame_provider_, unwrapper); + video_scaled_hw_->setBounds(gfx::Size(10, 10)); + video_scaled_hw_->setAnchorPoint(gfx::PointF()); + video_scaled_hw_->setIsDrawable(true); + root_->addChild(video_scaled_hw_); + + scoped_refptr<IOSurfaceLayer> io_surface_ = IOSurfaceLayer::create(); + io_surface_->setBounds(gfx::Size(10, 10)); + io_surface_->setAnchorPoint(gfx::PointF()); + io_surface_->setIsDrawable(true); + io_surface_->setIOSurfaceProperties(1, gfx::Size(10, 10)); + root_->addChild(io_surface_); + + scoped_refptr<HeadsUpDisplayLayer> hud_ = HeadsUpDisplayLayer::create(); + hud_->setBounds(gfx::Size(10, 10)); + hud_->setAnchorPoint(gfx::PointF()); + hud_->setIsDrawable(true); + root_->addChild(hud_); + // Enable the hud. + LayerTreeDebugState debug_state; + debug_state.showFPSCounter = true; + m_layerTreeHost->setDebugState(debug_state); + + bool paint_scrollbar = true; + bool has_thumb = true; + scoped_refptr<ScrollbarLayer> scrollbar_ = ScrollbarLayer::create( + FakeWebScrollbar::create().PassAs<WebKit::WebScrollbar>(), + FakeScrollbarThemePainter::Create(paint_scrollbar) + .PassAs<ScrollbarThemePainter>(), + FakeWebScrollbarThemeGeometry::create(has_thumb) + .PassAs<WebKit::WebScrollbarThemeGeometry>(), + content_->id()); + scrollbar_->setBounds(gfx::Size(10, 10)); + scrollbar_->setAnchorPoint(gfx::PointF()); + scrollbar_->setIsDrawable(true); + root_->addChild(scrollbar_); + + m_layerTreeHost->setRootLayer(root_); + LayerTreeHostContextTest::setupTree(); + } + + virtual void beginTest() OVERRIDE { + postSetNeedsCommitToMainThread(); + } + + virtual void commitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + ResourceProvider* resource_provider = host_impl->resourceProvider(); + + if (host_impl->activeTree()->source_frame_number() == 0) { + // Set up impl resources on the first commit. + + scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create(); + pass_for_quad->SetNew( + // AppendOneOfEveryQuadType() makes a RenderPass quad with this id. + RenderPass::Id(1, 1), + gfx::Rect(0, 0, 10, 10), + gfx::Rect(0, 0, 10, 10), + gfx::Transform()); + + scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); + pass->SetNew( + RenderPass::Id(2, 1), + gfx::Rect(0, 0, 10, 10), + gfx::Rect(0, 0, 10, 10), + gfx::Transform()); + pass->AppendOneOfEveryQuadType(resource_provider); + + ScopedPtrVector<RenderPass> pass_list; + pass_list.append(pass_for_quad.PassAs<RenderPass>()); + pass_list.append(pass.PassAs<RenderPass>()); + + // First child is the delegated layer. + DelegatedRendererLayerImpl* delegated_impl = + static_cast<DelegatedRendererLayerImpl*>( + host_impl->rootLayer()->children()[0]); + delegated_impl->setRenderPasses(pass_list); + EXPECT_TRUE(pass_list.isEmpty()); + + color_video_frame_ = make_scoped_ptr(new FakeVideoFrame( + VideoFrame::CreateColorFrame( + gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta()))); + hw_video_frame_ = make_scoped_ptr(new FakeVideoFrame( + VideoFrame::WrapNativeTexture( + resource_provider->graphicsContext3D()->createTexture(), + GL_TEXTURE_2D, + gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), + base::TimeDelta(), + VideoFrame::ReadPixelsCB(), + base::Closure()))); + scaled_hw_video_frame_ = make_scoped_ptr(new FakeVideoFrame( + VideoFrame::WrapNativeTexture( + resource_provider->graphicsContext3D()->createTexture(), + GL_TEXTURE_2D, + gfx::Size(4, 4), gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), + base::TimeDelta(), + VideoFrame::ReadPixelsCB(), + base::Closure()))); + + color_frame_provider_.set_frame(color_video_frame_.get()); + hw_frame_provider_.set_frame(hw_video_frame_.get()); + scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_.get()); + return; + } + + if (host_impl->activeTree()->source_frame_number() == 3) { + // On the third commit we're recovering from context loss. Hardware + // video frames should not be reused by the VideoFrameProvider, but + // software frames can be. + hw_frame_provider_.set_frame(NULL); + scaled_hw_frame_provider_.set_frame(NULL); + } + } + + virtual bool prepareToDrawOnThread(LayerTreeHostImpl* host_impl) { + if (host_impl->activeTree()->source_frame_number() == 2) { + // Lose the context during draw on the second commit. This will cause + // a third commit to recover. + if (context3d_) + context3d_->set_times_bind_texture_succeeds(4); + } + return true; + } + + virtual void didCommitAndDrawFrame() OVERRIDE { + // End the test once we know the 3nd frame drew. + if (m_layerTreeHost->commitNumber() == 4) + endTest(); + } + + virtual void afterTest() OVERRIDE {} + + private: + FakeContentLayerClient client_; + + scoped_refptr<Layer> root_; + scoped_refptr<DelegatedRendererLayer> delegated_; + scoped_refptr<ContentLayer> content_; + scoped_refptr<TextureLayer> texture_; + scoped_refptr<ContentLayer> mask_; + scoped_refptr<ContentLayer> content_with_mask_; + scoped_refptr<VideoLayer> video_color_; + scoped_refptr<VideoLayer> video_hw_; + scoped_refptr<VideoLayer> video_scaled_hw_; + scoped_refptr<IOSurfaceLayer> io_surface_; + scoped_refptr<HeadsUpDisplayLayer> hud_; + scoped_refptr<ScrollbarLayer> scrollbar_; + + scoped_ptr<FakeVideoFrame> color_video_frame_; + scoped_ptr<FakeVideoFrame> hw_video_frame_; + scoped_ptr<FakeVideoFrame> scaled_hw_video_frame_; + + FakeVideoFrameProvider color_frame_provider_; + FakeVideoFrameProvider hw_frame_provider_; + FakeVideoFrameProvider scaled_hw_frame_provider_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources) + +} // namespace +} // namespace cc |