| // Copyright 2019 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 "content/browser/renderer_host/compositor_dependencies_android.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/system/sys_info.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "cc/raster/single_thread_task_graph_runner.h" |
| #include "components/viz/client/frame_eviction_manager.h" |
| #include "content/browser/browser_main_loop.h" |
| #include "content/browser/gpu/browser_gpu_channel_host_factory.h" |
| #include "content/browser/gpu/gpu_data_manager_impl.h" |
| #include "content/browser/gpu/gpu_process_host.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/common/content_features.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| // The client_id used here should not conflict with the client_id generated |
| // from RenderWidgetHostImpl. |
| constexpr uint32_t kDefaultClientId = 0u; |
| |
| void BrowserGpuChannelHostFactorySetApplicationVisible(bool is_visible) { |
| // This code relies on the browser's GpuChannelEstablishFactory being the |
| // BrowserGpuChannelHostFactory. |
| DCHECK_EQ(BrowserMainLoop::GetInstance()->gpu_channel_establish_factory(), |
| BrowserGpuChannelHostFactory::instance()); |
| BrowserGpuChannelHostFactory::instance()->SetApplicationVisible(is_visible); |
| } |
| |
| // These functions are called based on application visibility status. |
| void SendOnBackgroundedToGpuService() { |
| content::GpuProcessHost::CallOnIO( |
| content::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */, |
| base::BindOnce([](content::GpuProcessHost* host) { |
| if (host) { |
| host->gpu_service()->OnBackgrounded(); |
| } |
| })); |
| } |
| |
| void SendOnForegroundedToGpuService() { |
| content::GpuProcessHost::CallOnIO( |
| content::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */, |
| base::BindOnce([](content::GpuProcessHost* host) { |
| if (host) { |
| host->gpu_service()->OnForegrounded(); |
| } |
| })); |
| } |
| |
| class SingleThreadTaskGraphRunner : public cc::SingleThreadTaskGraphRunner { |
| public: |
| SingleThreadTaskGraphRunner() { |
| Start("CompositorTileWorker1", base::SimpleThread::Options()); |
| } |
| |
| ~SingleThreadTaskGraphRunner() override { Shutdown(); } |
| }; |
| |
| } // namespace |
| |
| // static |
| CompositorDependenciesAndroid& CompositorDependenciesAndroid::Get() { |
| static base::NoDestructor<CompositorDependenciesAndroid> instance; |
| return *instance; |
| } |
| |
| CompositorDependenciesAndroid::CompositorDependenciesAndroid() |
| : frame_sink_id_allocator_(kDefaultClientId) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| |
| // Set up a callback to automatically re-connect if we lose our connection. |
| // Unretained is safe due to base::NoDestructor. |
| host_frame_sink_manager_.SetConnectionLostCallback(base::BindRepeating( |
| &CompositorDependenciesAndroid::CreateVizFrameSinkManager, |
| base::Unretained(this))); |
| |
| CreateVizFrameSinkManager(); |
| } |
| |
| CompositorDependenciesAndroid::~CompositorDependenciesAndroid() = default; |
| |
| void CompositorDependenciesAndroid::CreateVizFrameSinkManager() { |
| mojo::PendingRemote<viz::mojom::FrameSinkManager> frame_sink_manager; |
| mojo::PendingReceiver<viz::mojom::FrameSinkManager> |
| frame_sink_manager_receiver = |
| frame_sink_manager.InitWithNewPipeAndPassReceiver(); |
| mojo::PendingRemote<viz::mojom::FrameSinkManagerClient> |
| frame_sink_manager_client; |
| mojo::PendingReceiver<viz::mojom::FrameSinkManagerClient> |
| frame_sink_manager_client_receiver = |
| frame_sink_manager_client.InitWithNewPipeAndPassReceiver(); |
| |
| // Setup HostFrameSinkManager with interface endpoints. |
| host_frame_sink_manager_.BindAndSetManager( |
| std::move(frame_sink_manager_client_receiver), |
| base::ThreadTaskRunnerHandle::Get(), std::move(frame_sink_manager)); |
| |
| // Set up a pending request which will be run once we've successfully |
| // connected to the GPU process. |
| pending_connect_viz_on_main_thread_ = base::BindOnce( |
| &CompositorDependenciesAndroid::ConnectVizFrameSinkManagerOnMainThread, |
| std::move(frame_sink_manager_receiver), |
| std::move(frame_sink_manager_client), |
| host_frame_sink_manager_.debug_renderer_settings()); |
| } |
| |
| cc::TaskGraphRunner* CompositorDependenciesAndroid::GetTaskGraphRunner() { |
| if (!task_graph_runner_) |
| task_graph_runner_ = std::make_unique<SingleThreadTaskGraphRunner>(); |
| return task_graph_runner_.get(); |
| } |
| |
| viz::FrameSinkId CompositorDependenciesAndroid::AllocateFrameSinkId() { |
| return frame_sink_id_allocator_.NextFrameSinkId(); |
| } |
| |
| void CompositorDependenciesAndroid::TryEstablishVizConnectionIfNeeded() { |
| if (!pending_connect_viz_on_main_thread_) |
| return; |
| std::move(pending_connect_viz_on_main_thread_).Run(); |
| } |
| |
| // Called on the GpuProcessHost thread, after a GPU connection has already been |
| // established. |gpu_process_host| should only be invalid if a channel has been |
| // established and lost. In this case the ConnectionLost callback will be |
| // re-run when the request is deleted (goes out of scope). |
| // static |
| void CompositorDependenciesAndroid::ConnectVizFrameSinkManagerOnMainThread( |
| mojo::PendingReceiver<viz::mojom::FrameSinkManager> receiver, |
| mojo::PendingRemote<viz::mojom::FrameSinkManagerClient> client, |
| const viz::DebugRendererSettings& debug_renderer_settings) { |
| auto* gpu_process_host = GpuProcessHost::Get(); |
| if (!gpu_process_host) |
| return; |
| |
| gpu_process_host->gpu_host()->ConnectFrameSinkManager( |
| std::move(receiver), std::move(client), debug_renderer_settings); |
| } |
| |
| void CompositorDependenciesAndroid::EnqueueLowEndBackgroundCleanup() { |
| if (base::SysInfo::IsLowEndDevice()) { |
| low_end_background_cleanup_task_.Reset(base::BindOnce( |
| &CompositorDependenciesAndroid::DoLowEndBackgroundCleanup, |
| base::Unretained(this))); |
| base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| FROM_HERE, low_end_background_cleanup_task_.callback(), |
| base::Seconds(5)); |
| } |
| } |
| |
| void CompositorDependenciesAndroid::DoLowEndBackgroundCleanup() { |
| // When we become visible, we immediately cancel the callback that runs this |
| // code. First, evict all unlocked frames, allowing resources to be |
| // reclaimed. |
| viz::FrameEvictionManager::GetInstance()->PurgeAllUnlockedFrames(); |
| |
| // Next, notify the GPU process to do background processing, which will |
| // lose all renderer contexts. |
| content::GpuProcessHost::CallOnIO( |
| content::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */, |
| base::BindOnce([](content::GpuProcessHost* host) { |
| if (host) { |
| host->gpu_service()->OnBackgroundCleanup(); |
| } |
| })); |
| } |
| |
| void CompositorDependenciesAndroid::OnCompositorVisible( |
| CompositorImpl* compositor) { |
| bool element_inserted = visible_compositors_.insert(compositor).second; |
| DCHECK(element_inserted); |
| if (visible_compositors_.size() == 1) |
| OnVisibilityChanged(); |
| } |
| |
| void CompositorDependenciesAndroid::OnCompositorHidden( |
| CompositorImpl* compositor) { |
| size_t elements_removed = visible_compositors_.erase(compositor); |
| DCHECK_EQ(1u, elements_removed); |
| if (visible_compositors_.size() == 0) |
| OnVisibilityChanged(); |
| } |
| |
| // This function runs when our first CompositorImpl becomes visible or when |
| // our last Compositormpl is hidden. |
| void CompositorDependenciesAndroid::OnVisibilityChanged() { |
| if (visible_compositors_.size() > 0) { |
| GpuDataManagerImpl::GetInstance()->SetApplicationVisible(true); |
| BrowserGpuChannelHostFactorySetApplicationVisible(true); |
| SendOnForegroundedToGpuService(); |
| low_end_background_cleanup_task_.Cancel(); |
| } else { |
| GpuDataManagerImpl::GetInstance()->SetApplicationVisible(false); |
| BrowserGpuChannelHostFactorySetApplicationVisible(false); |
| SendOnBackgroundedToGpuService(); |
| EnqueueLowEndBackgroundCleanup(); |
| } |
| } |
| |
| } // namespace content |