// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/android/synchronous_compositor_sync_call_bridge.h"
#include <memory>
#include "base/functional/bind.h"
#include "content/browser/android/synchronous_compositor_host.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_features.h"
#include "ui/android/window_android.h"
namespace content {
SynchronousCompositorSyncCallBridge::SynchronousCompositorSyncCallBridge(
SynchronousCompositorHost* host)
: host_(host), begin_frame_condition_(&lock_) {
DCHECK(host);
}
SynchronousCompositorSyncCallBridge::~SynchronousCompositorSyncCallBridge() {
DCHECK(frame_futures_.empty());
}
void SynchronousCompositorSyncCallBridge::RemoteReady() {
base::AutoLock lock(lock_);
if (remote_state_ != RemoteState::INIT)
return;
remote_state_ = RemoteState::READY;
}
void SynchronousCompositorSyncCallBridge::RemoteClosedOnIOThread() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
base::AutoLock lock(lock_);
SignalRemoteClosedToAllWaitersOnIOThread();
}
bool SynchronousCompositorSyncCallBridge::ReceiveFrameOnIOThread(
int layer_tree_frame_sink_id,
uint32_t metadata_version,
std::optional<viz::LocalSurfaceId> local_surface_id,
std::optional<viz::CompositorFrame> compositor_frame,
std::optional<viz::HitTestRegionList> hit_test_region_list) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
base::AutoLock lock(lock_);
if (remote_state_ != RemoteState::READY || frame_futures_.empty())
return false;
auto frame_ptr = std::make_unique<SynchronousCompositor::Frame>();
frame_ptr->layer_tree_frame_sink_id = layer_tree_frame_sink_id;
scoped_refptr<SynchronousCompositor::FrameFuture> future =
std::move(frame_futures_.front());
DCHECK(future);
frame_futures_.pop_front();
if (compositor_frame) {
if (!local_surface_id)
return false;
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&SynchronousCompositorSyncCallBridge::
ProcessFrameMetadataOnUIThread,
this, metadata_version,
compositor_frame->metadata.Clone(),
local_surface_id.value()));
frame_ptr->frame = std::make_unique<viz::CompositorFrame>();
*frame_ptr->frame = std::move(*compositor_frame);
frame_ptr->local_surface_id = local_surface_id.value();
frame_ptr->hit_test_region_list = std::move(hit_test_region_list);
}
future->SetFrame(std::move(frame_ptr));
return true;
}
bool SynchronousCompositorSyncCallBridge::BeginFrameResponseOnIOThread(
blink::mojom::SyncCompositorCommonRendererParamsPtr render_params) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
base::AutoLock lock(lock_);
if (begin_frame_response_valid_)
return false;
begin_frame_response_valid_ = true;
last_render_params_ = *render_params;
begin_frame_condition_.Signal();
return true;
}
bool SynchronousCompositorSyncCallBridge::WaitAfterVSyncOnUIThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::AutoLock lock(lock_);
if (remote_state_ != RemoteState::READY)
return false;
CHECK(!begin_frame_response_valid_);
host_->AddBeginFrameCompletionCallback(base::BindOnce(
&SynchronousCompositorSyncCallBridge::BeginFrameCompleteOnUIThread,
this));
return true;
}
bool SynchronousCompositorSyncCallBridge::SetFrameFutureOnUIThread(
scoped_refptr<SynchronousCompositor::FrameFuture> frame_future) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(frame_future);
base::AutoLock lock(lock_);
if (remote_state_ != RemoteState::READY)
return false;
// Allowing arbitrary number of pending futures can lead to increase in frame
// latency. Due to this, Android platform already ensures that here that there
// can be at most 2 pending frames. Here, we rely on Android to do the
// necessary blocking, which allows more parallelism without increasing
// latency. But DCHECK Android blocking is working.
DCHECK_LT(frame_futures_.size(), 2u);
frame_futures_.emplace_back(std::move(frame_future));
return true;
}
void SynchronousCompositorSyncCallBridge::HostDestroyedOnUIThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(host_);
host_ = nullptr;
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
&SynchronousCompositorSyncCallBridge::CloseHostControlOnIOThread,
this));
}
bool SynchronousCompositorSyncCallBridge::IsRemoteReadyOnUIThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::AutoLock lock(lock_);
return remote_state_ == RemoteState::READY;
}
void SynchronousCompositorSyncCallBridge::BeginFrameCompleteOnUIThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
blink::mojom::SyncCompositorCommonRendererParamsPtr render_params;
{
base::AutoLock lock(lock_);
if (remote_state_ != RemoteState::READY)
return;
// If we haven't received a response yet. Wait for it.
if (!begin_frame_response_valid_) {
base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope
allow_base_sync_primitives;
while (!begin_frame_response_valid_ &&
remote_state_ == RemoteState::READY) {
begin_frame_condition_.Wait();
}
}
DCHECK(begin_frame_response_valid_ || remote_state_ != RemoteState::READY);
begin_frame_response_valid_ = false;
if (remote_state_ == RemoteState::READY) {
render_params = last_render_params_.Clone();
}
}
if (render_params) {
host_->BeginFrameComplete(std::move(render_params));
}
}
void SynchronousCompositorSyncCallBridge::ProcessFrameMetadataOnUIThread(
uint32_t metadata_version,
viz::CompositorFrameMetadata metadata,
const viz::LocalSurfaceId& local_surface_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (host_) {
host_->UpdateFrameMetaData(metadata_version, std::move(metadata),
local_surface_id);
}
}
void SynchronousCompositorSyncCallBridge::
SignalRemoteClosedToAllWaitersOnIOThread() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
lock_.AssertAcquired();
remote_state_ = RemoteState::CLOSED;
for (auto& future_ptr : frame_futures_) {
future_ptr->SetFrame(nullptr);
}
frame_futures_.clear();
begin_frame_condition_.Signal();
}
void SynchronousCompositorSyncCallBridge::SetHostControlReceiverOnIOThread(
mojo::SelfOwnedReceiverRef<blink::mojom::SynchronousCompositorControlHost>
host_control_receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
host_control_receiver_ = host_control_receiver;
}
void SynchronousCompositorSyncCallBridge::CloseHostControlOnIOThread() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (host_control_receiver_) {
host_control_receiver_->Close();
host_control_receiver_.reset();
}
}
} // namespace content