text: // Copyright 2018 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/android/synchronous_compositor_sync_call_bridge.h"
  
  #include <memory>
  
  #include "base/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,
      absl::optional<viz::LocalSurfaceId> local_surface_id,
      absl::optional<viz::CompositorFrame> compositor_frame,
      absl::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_->UpdateState(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
  