1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168

content / browser / android / synchronous_compositor_sync_call_bridge.h [blame]

// 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.

#ifndef CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_SYNC_CALL_BRIDGE_H_
#define CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_SYNC_CALL_BRIDGE_H_

#include <optional>

#include "base/containers/circular_deque.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/condition_variable.h"
#include "base/thread_annotations.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "content/public/browser/android/synchronous_compositor.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "third_party/blink/public/mojom/input/synchronous_compositor.mojom.h"

namespace content {

class SynchronousCompositorHost;

// For the synchronous compositor feature of webview it is necessary
// that the UI thread to block until the renderer process has processed
// certain messages entirely. (beginframe and resulting compositor frames).
// This object is used to manage the waiting and signaling behavior on the UI
// thread. The UI thread will wait on a WaitableEvent (via FrameFuture class)
// or condition variable which is then signal by handlers in this class.
// This object is a cross thread object accessed both on the UI and IO threads.
//
// Examples of call graphs are:
//    Browser UI Thread         Browser IO Thread       Renderer
//
//  ->VSync Java
//      ----------------------------------------------->BeginFrame
//      CV Wait
//                                BeginFrameRes<----------
//                                CVSignal
//      WakeUp
//
//
//  ->DrawHwAsync
//      RegisterFrameFuture
//      ----------------------------------------------->DrawHwAsync
//      Do some stuff
//      FrameFuture::GetFrame()
//        WaitableEvent::Wait()
//                             ReceiveFrame<---------------
//                             WaitableEvent::Signal()
//      WakeUp
//
// This may seem simple but it gets a little more complicated when
// multiple views are involved. Each view will have it's own SyncCallBridge.
//
//   Once example is:
//
//    Browser UI Thread         Browser IO Thread       Renderer1    Renderer2
//
//  ->VSync Java
//      ----------------------------------------------->BeginFrame
//                                BeginFrameRes<----------
//                                CVSignal
//      ------------------------------------------------------------>BeginFrame
//      CV Wait
//                                BeginFrameRes<----------------------------
//                                CVSignal
//      WakeUp
//
// Notice that it is possible that before we wait on a CV variable a renderer
// may have already responded to the BeginFrame request.
//
class SynchronousCompositorSyncCallBridge
    : public base::RefCountedThreadSafe<SynchronousCompositorSyncCallBridge> {
 public:
  explicit SynchronousCompositorSyncCallBridge(SynchronousCompositorHost* host);

  SynchronousCompositorSyncCallBridge(
      const SynchronousCompositorSyncCallBridge&) = delete;
  SynchronousCompositorSyncCallBridge& operator=(
      const SynchronousCompositorSyncCallBridge&) = delete;

  // Indicatation that the remote is now ready to process requests. Called
  // on either UI or IO thread.
  void RemoteReady();

  // Remote channel is closed signal all waiters.
  void RemoteClosedOnIOThread();

  // Receive a frame. Return false if the corresponding frame wasn't found.
  bool ReceiveFrameOnIOThread(
      int frame_sink_id,
      uint32_t metadata_version,
      std::optional<viz::LocalSurfaceId> local_surface_id,
      std::optional<viz::CompositorFrame>,
      std::optional<viz::HitTestRegionList> hit_test_region_list);

  // Receive a BeginFrameResponse. Returns true if handling the response was
  // successful or not.
  bool BeginFrameResponseOnIOThread(
      blink::mojom::SyncCompositorCommonRendererParamsPtr render_params);

  // Schedule a callback for when vsync finishes and wait for the
  // BeginFrameResponse callback.
  bool WaitAfterVSyncOnUIThread();

  // Store a FrameFuture for a later ReceiveFrame callback. Return if the
  // future was stored for further handling.
  bool SetFrameFutureOnUIThread(
      scoped_refptr<SynchronousCompositor::FrameFuture> frame_future);

  // Indicate the host is destroyed.
  void HostDestroyedOnUIThread();

  // Return whether the remote side is ready.
  bool IsRemoteReadyOnUIThread();

  // Set a weak reference to host control receiver then we can close the host
  // control when the host was destroyed.
  void SetHostControlReceiverOnIOThread(
      mojo::SelfOwnedReceiverRef<blink::mojom::SynchronousCompositorControlHost>
          host_control_receiver);

 private:
  friend class base::RefCountedThreadSafe<SynchronousCompositorSyncCallBridge>;
  ~SynchronousCompositorSyncCallBridge();

  // Callback passed to WindowAndroid, runs when the current begin frame is
  // completed.
  void BeginFrameCompleteOnUIThread();

  // Process metadata.
  void ProcessFrameMetadataOnUIThread(
      uint32_t metadata_version,
      viz::CompositorFrameMetadata metadata,
      const viz::LocalSurfaceId& local_surface_id);

  // Signal all waiters for closure. Callee must host a lock to |lock_|.
  void SignalRemoteClosedToAllWaitersOnIOThread()
      EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // Close the host control on io thread.
  void CloseHostControlOnIOThread();

  using FrameFutureQueue =
      base::circular_deque<scoped_refptr<SynchronousCompositor::FrameFuture>>;

  enum class RemoteState { INIT, READY, CLOSED };

  // UI thread only.
  raw_ptr<SynchronousCompositorHost> host_;
  // This handles the host control receiver in browser side.
  mojo::SelfOwnedReceiverRef<blink::mojom::SynchronousCompositorControlHost>
      host_control_receiver_;

  // Shared variables between the IO thread and UI thread.
  base::Lock lock_;
  FrameFutureQueue frame_futures_ GUARDED_BY(lock_);
  bool begin_frame_response_valid_ GUARDED_BY(lock_) = false;
  blink::mojom::SyncCompositorCommonRendererParams last_render_params_
      GUARDED_BY(lock_);
  base::ConditionVariable begin_frame_condition_ GUARDED_BY(lock_);
  RemoteState remote_state_ GUARDED_BY(lock_) = RemoteState::INIT;
};

}  // namespace content

#endif  // CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_SYNC_CALL_BRIDGE_H_