chromium/android_webview/browser/gfx/root_frame_sink_proxy.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/gfx/root_frame_sink_proxy.h"

#include <utility>

#include "android_webview/browser/gfx/root_frame_sink.h"
#include "android_webview/browser/gfx/viz_compositor_thread_runner_webview.h"
#include "base/memory/raw_ptr.h"
#include "base/task/single_thread_task_runner.h"

namespace android_webview {

class RootFrameSinkProxy::RootFrameSinkClientImpl : public RootFrameSinkClient {
 public:
  RootFrameSinkClientImpl(RootFrameSinkProxy* owner) : owner_(owner) {}
  ~RootFrameSinkClientImpl() override = default;

  // RootFrameSinkClient implementation
  void SetNeedsBeginFrames(bool needs_begin_frame) override {
    owner_->SetNeedsBeginFramesOnViz(needs_begin_frame);
  }
  void Invalidate() override { owner_->InvalidateOnViz(); }
  void ReturnResources(viz::FrameSinkId frame_sink_id,
                       uint32_t layer_tree_frame_sink_id,
                       std::vector<viz::ReturnedResource> resources) override {
    owner_->ReturnResourcesOnViz(frame_sink_id, layer_tree_frame_sink_id,
                                 std::move(resources));
  }
  void OnCompositorFrameTransitionDirectiveProcessed(
      viz::FrameSinkId frame_sink_id,
      uint32_t layer_tree_frame_sink_id,
      uint32_t sequence_id) override {
    owner_->OnCompositorFrameTransitionDirectiveProcessedOnViz(
        frame_sink_id, layer_tree_frame_sink_id, sequence_id);
  }

 private:
  const raw_ptr<RootFrameSinkProxy> owner_;
};

// static
scoped_refptr<RootFrameSink> RootFrameSinkProxy::GetRootFrameSinkHelper(
    base::WeakPtr<RootFrameSinkProxy> proxy) {
  DCHECK(VizCompositorThreadRunnerWebView::GetInstance()
             ->task_runner()
             ->BelongsToCurrentThread());
  if (proxy)
    return proxy->without_gpu_;
  return nullptr;
}

RootFrameSinkProxy::RootFrameSinkProxy(
    const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
    RootFrameSinkProxyClient* client,
    viz::BeginFrameSource* begin_frame_source)
    : ui_task_runner_(ui_task_runner),
      viz_task_runner_(
          VizCompositorThreadRunnerWebView::GetInstance()->task_runner()),
      client_(client),
      begin_frame_source_(begin_frame_source) {
  DETACH_FROM_THREAD(viz_thread_checker_);
  viz_task_runner_->PostTask(
      FROM_HERE, base::BindOnce(&RootFrameSinkProxy::InitializeOnViz,
                                base::Unretained(this)));
}

void RootFrameSinkProxy::InitializeOnViz() {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  root_frame_sink_client_ = std::make_unique<RootFrameSinkClientImpl>(this);
  without_gpu_ =
      base::MakeRefCounted<RootFrameSink>(root_frame_sink_client_.get());
}

RootFrameSinkProxy::~RootFrameSinkProxy() {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  VizCompositorThreadRunnerWebView::GetInstance()->PostTaskAndBlock(
      FROM_HERE, base::BindOnce(&RootFrameSinkProxy::DestroyOnViz,
                                base::Unretained(this)));
  if (observing_bfs_)
    begin_frame_source_->RemoveObserver(this);
}

void RootFrameSinkProxy::DestroyOnViz() {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  without_gpu_->DettachClient();
  without_gpu_.reset();
  weak_ptr_factory_on_viz_.InvalidateWeakPtrs();
  root_frame_sink_client_.reset();
}

void RootFrameSinkProxy::SetNeedsBeginFramesOnViz(bool needs_begin_frames) {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  ui_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&RootFrameSinkProxy::SetNeedsBeginFramesOnUI,
                     weak_ptr_factory_.GetWeakPtr(), needs_begin_frames));
}

void RootFrameSinkProxy::SetNeedsBeginFramesOnUI(bool needs_begin_frames) {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  if (observing_bfs_ == needs_begin_frames)
    return;

  observing_bfs_ = needs_begin_frames;

  if (needs_begin_frames)
    begin_frame_source_->AddObserver(this);
  else
    begin_frame_source_->RemoveObserver(this);
}

void RootFrameSinkProxy::InvalidateOnViz() {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  ui_task_runner_->PostTask(FROM_HERE,
                            base::BindOnce(&RootFrameSinkProxy::InvalidateOnUI,
                                           weak_ptr_factory_.GetWeakPtr()));
}

void RootFrameSinkProxy::InvalidateOnUI() {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  client_->Invalidate();
}

void RootFrameSinkProxy::AddChildFrameSinkId(
    const viz::FrameSinkId& frame_sink_id) {
  DCHECK_NE(frame_sink_id.client_id(), 0u);
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  viz_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&RootFrameSinkProxy::AddChildFrameSinkIdOnViz,
                     weak_ptr_factory_on_viz_.GetWeakPtr(), frame_sink_id));
}

void RootFrameSinkProxy::AddChildFrameSinkIdOnViz(
    const viz::FrameSinkId& frame_sink_id) {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  without_gpu_->AddChildFrameSinkId(frame_sink_id);
}

void RootFrameSinkProxy::RemoveChildFrameSinkId(
    const viz::FrameSinkId& frame_sink_id) {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  viz_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&RootFrameSinkProxy::RemoveChildFrameSinkIdOnViz,
                     weak_ptr_factory_on_viz_.GetWeakPtr(), frame_sink_id));
}

void RootFrameSinkProxy::RemoveChildFrameSinkIdOnViz(
    const viz::FrameSinkId& frame_sink_id) {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  without_gpu_->RemoveChildFrameSinkId(frame_sink_id);
}

void RootFrameSinkProxy::OnInputEvent() {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  had_input_event_ = true;
}

bool RootFrameSinkProxy::BeginFrame(const viz::BeginFrameArgs& args) {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  bool invalidate = false;
  VizCompositorThreadRunnerWebView::GetInstance()->PostTaskAndBlock(
      FROM_HERE, base::BindOnce(&RootFrameSinkProxy::BeginFrameOnViz,
                                base::Unretained(this), args, had_input_event_,
                                &invalidate));
  had_input_event_ = false;
  return invalidate;
}

void RootFrameSinkProxy::BeginFrameOnViz(const viz::BeginFrameArgs& args,
                                         bool had_input_event,
                                         bool* invalidate) {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  *invalidate = without_gpu_->BeginFrame(args, had_input_event);
}

void RootFrameSinkProxy::SetBeginFrameSourcePausedOnViz(bool paused) {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  without_gpu_->SetBeginFrameSourcePaused(paused);
}

RootFrameSinkGetter RootFrameSinkProxy::GetRootFrameSinkCallback() {
  return base::BindRepeating(&RootFrameSinkProxy::GetRootFrameSinkHelper,
                             weak_ptr_factory_on_viz_.GetWeakPtr());
}

void RootFrameSinkProxy::OnBeginFrameSourcePausedChanged(bool paused) {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  viz_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&RootFrameSinkProxy::SetBeginFrameSourcePausedOnViz,
                     weak_ptr_factory_on_viz_.GetWeakPtr(), paused));
}

bool RootFrameSinkProxy::OnBeginFrameDerivedImpl(
    const viz::BeginFrameArgs& args) {
  DCHECK(client_);
  if (BeginFrame(args))
    client_->Invalidate();

  return true;
}

void RootFrameSinkProxy::ReturnResourcesOnUI(
    viz::FrameSinkId frame_sink_id,
    uint32_t layer_tree_frame_sink_id,
    std::vector<viz::ReturnedResource> resources) {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  client_->ReturnResourcesFromViz(frame_sink_id, layer_tree_frame_sink_id,
                                  std::move(resources));
}
void RootFrameSinkProxy::ReturnResourcesOnViz(
    viz::FrameSinkId frame_sink_id,
    uint32_t layer_tree_frame_sink_id,
    std::vector<viz::ReturnedResource> resources) {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  ui_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&RootFrameSinkProxy::ReturnResourcesOnUI,
                     weak_ptr_factory_.GetWeakPtr(), frame_sink_id,
                     layer_tree_frame_sink_id, std::move(resources)));
}

void RootFrameSinkProxy::OnCompositorFrameTransitionDirectiveProcessedOnUI(
    viz::FrameSinkId frame_sink_id,
    uint32_t layer_tree_frame_sink_id,
    uint32_t sequence_id) {
  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
  client_->OnCompositorFrameTransitionDirectiveProcessed(
      frame_sink_id, layer_tree_frame_sink_id, sequence_id);
}

void RootFrameSinkProxy::OnCompositorFrameTransitionDirectiveProcessedOnViz(
    viz::FrameSinkId frame_sink_id,
    uint32_t layer_tree_frame_sink_id,
    uint32_t sequence_id) {
  DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_);
  ui_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&RootFrameSinkProxy::
                         OnCompositorFrameTransitionDirectiveProcessedOnUI,
                     weak_ptr_factory_.GetWeakPtr(), frame_sink_id,
                     layer_tree_frame_sink_id, sequence_id));
}

}  // namespace android_webview