#include "content/browser/renderer_host/compositor_dependencies_android.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/no_destructor.h"
#include "base/system/sys_info.h"
#include "base/task/single_thread_task_runner.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 {
constexpr uint32_t kDefaultClientId = 0u;
void BrowserGpuChannelHostFactorySetApplicationVisible(bool is_visible) {
DCHECK_EQ(BrowserMainLoop::GetInstance()->gpu_channel_establish_factory(),
BrowserGpuChannelHostFactory::instance());
BrowserGpuChannelHostFactory::instance()->SetApplicationVisible(is_visible);
}
void SendOnBackgroundedToGpuService() {
content::GpuProcessHost::CallOnIO(
FROM_HERE, content::GPU_PROCESS_KIND_SANDBOXED, false ,
base::BindOnce([](content::GpuProcessHost* host) {
if (host) {
host->gpu_service()->OnBackgrounded();
}
}));
}
void SendOnForegroundedToGpuService() {
content::GpuProcessHost::CallOnIO(
FROM_HERE, content::GPU_PROCESS_KIND_SANDBOXED, false ,
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(); }
};
}
CompositorDependenciesAndroid& CompositorDependenciesAndroid::Get() {
static base::NoDestructor<CompositorDependenciesAndroid> instance;
return *instance;
}
CompositorDependenciesAndroid::CompositorDependenciesAndroid()
: frame_sink_id_allocator_(kDefaultClientId) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
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();
host_frame_sink_manager_.BindAndSetManager(
std::move(frame_sink_manager_client_receiver),
base::SingleThreadTaskRunner::GetCurrentDefault(),
std::move(frame_sink_manager));
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();
}
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::IsLowEndDeviceOrPartialLowEndModeEnabled()) {
low_end_background_cleanup_task_.Reset(base::BindOnce(
&CompositorDependenciesAndroid::DoLowEndBackgroundCleanup,
base::Unretained(this)));
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, low_end_background_cleanup_task_.callback(),
base::Seconds(5));
}
}
void CompositorDependenciesAndroid::DoLowEndBackgroundCleanup() {
viz::FrameEvictionManager::GetInstance()->PurgeAllUnlockedFrames();
content::GpuProcessHost::CallOnIO(
FROM_HERE, content::GPU_PROCESS_KIND_SANDBOXED, false ,
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();
}
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();
}
}
}