| // Copyright 2017 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/mojo_embedder/async_layer_tree_frame_sink.h" |
| |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/threading/thread.h" |
| #include "cc/test/fake_layer_tree_frame_sink_client.h" |
| #include "components/viz/client/local_surface_id_provider.h" |
| #include "components/viz/test/test_context_provider.h" |
| #include "components/viz/test/test_gpu_memory_buffer_manager.h" |
| #include "mojo/public/cpp/bindings/interface_request.h" |
| #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace cc { |
| namespace mojo_embedder { |
| namespace { |
| |
| // Used to track the thread DidLoseLayerTreeFrameSink() is called on (and quit |
| // a RunLoop). |
| class ThreadTrackingLayerTreeFrameSinkClient |
| : public FakeLayerTreeFrameSinkClient { |
| public: |
| ThreadTrackingLayerTreeFrameSinkClient( |
| base::PlatformThreadId* called_thread_id, |
| base::RunLoop* run_loop) |
| : called_thread_id_(called_thread_id), run_loop_(run_loop) {} |
| ~ThreadTrackingLayerTreeFrameSinkClient() override = default; |
| |
| // FakeLayerTreeFrameSinkClient: |
| void DidLoseLayerTreeFrameSink() override { |
| EXPECT_FALSE(did_lose_layer_tree_frame_sink_called()); |
| FakeLayerTreeFrameSinkClient::DidLoseLayerTreeFrameSink(); |
| *called_thread_id_ = base::PlatformThread::CurrentId(); |
| run_loop_->Quit(); |
| } |
| |
| private: |
| base::PlatformThreadId* called_thread_id_; |
| base::RunLoop* run_loop_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ThreadTrackingLayerTreeFrameSinkClient); |
| }; |
| |
| TEST(AsyncLayerTreeFrameSinkTest, |
| DidLoseLayerTreeFrameSinkCalledOnConnectionError) { |
| base::Thread bg_thread("BG Thread"); |
| bg_thread.Start(); |
| |
| scoped_refptr<viz::TestContextProvider> provider = |
| viz::TestContextProvider::Create(); |
| viz::TestGpuMemoryBufferManager test_gpu_memory_buffer_manager; |
| |
| viz::mojom::CompositorFrameSinkPtrInfo sink_info; |
| viz::mojom::CompositorFrameSinkRequest sink_request = |
| mojo::MakeRequest(&sink_info); |
| viz::mojom::CompositorFrameSinkClientPtr client; |
| viz::mojom::CompositorFrameSinkClientRequest client_request = |
| mojo::MakeRequest(&client); |
| |
| AsyncLayerTreeFrameSink::InitParams init_params; |
| init_params.compositor_task_runner = bg_thread.task_runner(); |
| init_params.gpu_memory_buffer_manager = &test_gpu_memory_buffer_manager; |
| init_params.pipes.compositor_frame_sink_info = std::move(sink_info); |
| init_params.pipes.client_request = std::move(client_request); |
| init_params.local_surface_id_provider = |
| std::make_unique<viz::DefaultLocalSurfaceIdProvider>(); |
| init_params.enable_surface_synchronization = true; |
| auto layer_tree_frame_sink = std::make_unique<AsyncLayerTreeFrameSink>( |
| std::move(provider), nullptr, &init_params); |
| |
| base::PlatformThreadId called_thread_id = base::kInvalidThreadId; |
| base::RunLoop close_run_loop; |
| ThreadTrackingLayerTreeFrameSinkClient frame_sink_client(&called_thread_id, |
| &close_run_loop); |
| |
| auto bind_in_background = |
| [](AsyncLayerTreeFrameSink* layer_tree_frame_sink, |
| ThreadTrackingLayerTreeFrameSinkClient* frame_sink_client) { |
| layer_tree_frame_sink->BindToClient(frame_sink_client); |
| }; |
| bg_thread.task_runner()->PostTask( |
| FROM_HERE, base::BindOnce(bind_in_background, |
| base::Unretained(layer_tree_frame_sink.get()), |
| base::Unretained(&frame_sink_client))); |
| // Closes the pipe, which should trigger calling DidLoseLayerTreeFrameSink() |
| // (and quitting the RunLoop). There is no need to wait for BindToClient() |
| // to complete as mojo::Binding error callbacks are processed asynchronously. |
| sink_request = viz::mojom::CompositorFrameSinkRequest(); |
| close_run_loop.Run(); |
| |
| EXPECT_NE(base::kInvalidThreadId, called_thread_id); |
| EXPECT_EQ(called_thread_id, bg_thread.GetThreadId()); |
| |
| // DetachFromClient() has to be called on the background thread. |
| base::RunLoop detach_run_loop; |
| auto detach_in_background = |
| [](std::unique_ptr<AsyncLayerTreeFrameSink> layer_tree_frame_sink, |
| base::RunLoop* detach_run_loop) { |
| layer_tree_frame_sink->DetachFromClient(); |
| detach_run_loop->Quit(); |
| }; |
| bg_thread.task_runner()->PostTask( |
| FROM_HERE, |
| base::BindOnce(detach_in_background, std::move(layer_tree_frame_sink), |
| base::Unretained(&detach_run_loop))); |
| detach_run_loop.Run(); |
| } |
| |
| } // namespace |
| } // namespace mojo_embedder |
| } // namespace cc |