blob: c356bb35913218548da36548ac1f9ac5d4ab2a57 [file] [log] [blame]
// 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