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_