// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/message_loop/message_loop_proxy.h" #include "base/threading/simple_thread.h" #include "cc/layers/delegated_frame_provider.h" #include "cc/layers/delegated_frame_resource_collection.h" #include "cc/layers/delegated_renderer_layer.h" #include "cc/layers/layer.h" #include "cc/layers/solid_color_layer.h" #include "cc/output/delegated_frame_data.h" #include "cc/output/output_surface.h" #include "cc/output/output_surface_client.h" #include "cc/resources/resource_provider.h" #include "cc/scheduler/begin_frame_source.h" #include "cc/test/fake_delegated_renderer_layer.h" #include "cc/test/test_context_provider.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_single_thread_client.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/frame_time.h" namespace cc { namespace { class NoMessageLoopOutputSurface : public OutputSurface { public: NoMessageLoopOutputSurface() : OutputSurface(TestContextProvider::Create()) {} ~NoMessageLoopOutputSurface() override {} // OutputSurface overrides. void SwapBuffers(CompositorFrame* frame) override { DCHECK(client_); client_->DidSwapBuffers(); client_->DidSwapBuffersComplete(); } }; class LayerTreeHostNoMessageLoopTest : public testing::Test, public base::DelegateSimpleThread::Delegate, public LayerTreeHostClient, public LayerTreeHostSingleThreadClient { public: LayerTreeHostNoMessageLoopTest() : did_initialize_output_surface_(false), did_commit_(false), did_commit_and_draw_frame_(false), size_(100, 100), no_loop_thread_(this, "LayerTreeHostNoMessageLoopTest") {} ~LayerTreeHostNoMessageLoopTest() override {} // LayerTreeHostClient overrides. void WillBeginMainFrame(int frame_id) override {} void BeginMainFrame(const BeginFrameArgs& args) override {} void DidBeginMainFrame() override {} void Layout() override {} void ApplyViewportDeltas(const gfx::Vector2d& inner_delta, const gfx::Vector2d& outer_delta, const gfx::Vector2dF& elastic_overscroll_delta, float page_scale, float top_controls_delta) override {} void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta, float page_scale, float top_controls_delta) override {} void RequestNewOutputSurface() override { layer_tree_host_->SetOutputSurface( make_scoped_ptr(new NoMessageLoopOutputSurface)); } void DidInitializeOutputSurface() override { did_initialize_output_surface_ = true; } void DidFailToInitializeOutputSurface() override {} void WillCommit() override {} void DidCommit() override { did_commit_ = true; } void DidCommitAndDrawFrame() override { did_commit_and_draw_frame_ = true; } void DidCompleteSwapBuffers() override {} // LayerTreeHostSingleThreadClient overrides. void DidPostSwapBuffers() override {} void DidAbortSwapBuffers() override {} void RunTest() { no_loop_thread_.Start(); no_loop_thread_.Join(); } // base::DelegateSimpleThread::Delegate override. void Run() override { ASSERT_FALSE(base::MessageLoopProxy::current().get()); RunTestWithoutMessageLoop(); EXPECT_FALSE(base::MessageLoopProxy::current().get()); } protected: virtual void RunTestWithoutMessageLoop() = 0; void SetupLayerTreeHost() { LayerTreeSettings settings; settings.single_thread_proxy_scheduler = false; settings.verify_property_trees = true; layer_tree_host_ = LayerTreeHost::CreateSingleThreaded( this, this, nullptr, nullptr, settings, nullptr, nullptr); layer_tree_host_->SetViewportSize(size_); layer_tree_host_->SetRootLayer(root_layer_); } void Composite() { did_commit_ = false; did_commit_and_draw_frame_ = false; layer_tree_host_->Composite(gfx::FrameTime::Now()); EXPECT_TRUE(did_initialize_output_surface_); EXPECT_TRUE(did_commit_); EXPECT_TRUE(did_commit_and_draw_frame_); } void TearDownLayerTreeHost() { // Explicit teardown to make failures easier to debug. layer_tree_host_ = nullptr; root_layer_ = nullptr; } // All protected member variables are accessed only on |no_loop_thread_|. scoped_ptr layer_tree_host_; scoped_refptr root_layer_; bool did_initialize_output_surface_; bool did_commit_; bool did_commit_and_draw_frame_; gfx::Size size_; private: base::DelegateSimpleThread no_loop_thread_; }; class LayerTreeHostNoMessageLoopSmokeTest : public LayerTreeHostNoMessageLoopTest { protected: void RunTestWithoutMessageLoop() override { gfx::Size size(100, 100); // Set up root layer. { scoped_refptr solid_color_layer = SolidColorLayer::Create(); solid_color_layer->SetBackgroundColor(SK_ColorRED); solid_color_layer->SetBounds(size_); solid_color_layer->SetIsDrawable(true); root_layer_ = solid_color_layer; } SetupLayerTreeHost(); Composite(); TearDownLayerTreeHost(); } }; TEST_F(LayerTreeHostNoMessageLoopSmokeTest, SmokeTest) { RunTest(); } class LayerTreeHostNoMessageLoopDelegatedLayer : public LayerTreeHostNoMessageLoopTest, public DelegatedFrameResourceCollectionClient { protected: void RunTestWithoutMessageLoop() override { resource_collection_ = new DelegatedFrameResourceCollection; frame_provider_ = new DelegatedFrameProvider( resource_collection_.get(), CreateFrameDataWithResource(998)); root_layer_ = Layer::Create(); delegated_layer_ = FakeDelegatedRendererLayer::Create(frame_provider_.get()); delegated_layer_->SetBounds(size_); delegated_layer_->SetIsDrawable(true); root_layer_->AddChild(delegated_layer_); SetupLayerTreeHost(); // Draw first frame. Composite(); // Prepare and draw second frame. frame_provider_->SetFrameData(CreateFrameDataWithResource(999)); Composite(); // Resource from first frame should be returned. CheckReturnedResource(1u); TearDownLayerTreeHost(); delegated_layer_ = NULL; frame_provider_ = NULL; // Resource from second frame should be returned. CheckReturnedResource(1u); resource_collection_ = NULL; } // DelegatedFrameResourceCollectionClient overrides. void UnusedResourcesAreAvailable() override {} private: scoped_ptr CreateFrameDataWithResource( ResourceProvider::ResourceId resource_id) { scoped_ptr frame(new DelegatedFrameData); gfx::Rect frame_rect(size_); scoped_ptr root_pass(RenderPass::Create()); root_pass->SetNew( RenderPassId(1, 1), frame_rect, frame_rect, gfx::Transform()); frame->render_pass_list.push_back(root_pass.Pass()); TransferableResource resource; resource.id = resource_id; resource.mailbox_holder.texture_target = GL_TEXTURE_2D; resource.mailbox_holder.mailbox = gpu::Mailbox::Generate(); frame->resource_list.push_back(resource); return frame.Pass(); } void CheckReturnedResource(size_t expected_num) { ReturnedResourceArray returned_resources; resource_collection_->TakeUnusedResourcesForChildCompositor( &returned_resources); EXPECT_EQ(expected_num, returned_resources.size()); } scoped_refptr resource_collection_; scoped_refptr frame_provider_; scoped_refptr delegated_layer_; }; TEST_F(LayerTreeHostNoMessageLoopDelegatedLayer, SingleDelegatedLayer) { RunTest(); } } // namespace } // namespace cc