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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_APZUpdater_h
#define mozilla_layers_APZUpdater_h
#include <deque>
#include <unordered_map>
#include "base/platform_thread.h" // for PlatformThreadId
#include "LayersTypes.h"
#include "mozilla/layers/APZTestData.h"
#include "mozilla/layers/WebRenderScrollData.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "nsThreadUtils.h"
#include "Units.h"
namespace mozilla {
namespace layers {
class APZCTreeManager;
class FocusTarget;
class WebRenderScrollData;
/**
* This interface is used to send updates or otherwise mutate APZ internal
* state. These functions is usually called from the compositor thread in
* response to IPC messages. The method implementations internally redispatch
* themselves to the updater thread in the case where the compositor thread
* is not the updater thread.
*/
class APZUpdater {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZUpdater)
public:
APZUpdater(const RefPtr<APZCTreeManager>& aApz, bool aConnectedToWebRender);
bool HasTreeManager(const RefPtr<APZCTreeManager>& aApz);
void SetWebRenderWindowId(const wr::WindowId& aWindowId);
/**
* This function is invoked from rust on the scene builder thread when it
* is created. It effectively tells the APZUpdater "the current thread is
* the updater thread for this window id" and allows APZUpdater to remember
* which thread it is.
*/
static void SetUpdaterThread(const wr::WrWindowId& aWindowId);
static void PrepareForSceneSwap(const wr::WrWindowId& aWindowId);
static void CompleteSceneSwap(const wr::WrWindowId& aWindowId,
const wr::WrPipelineInfo& aInfo);
static void ProcessPendingTasks(const wr::WrWindowId& aWindowId);
void ClearTree(LayersId aRootLayersId);
void UpdateFocusState(LayersId aRootLayerTreeId,
LayersId aOriginatingLayersId,
const FocusTarget& aFocusTarget);
/**
* This should be called (in the WR-enabled case) when the compositor receives
* a new WebRenderScrollData for a layers id. The |aScrollData| parameter is
* the scroll data for |aOriginatingLayersId| and |aEpoch| is the
* corresponding epoch for the transaction that transferred the scroll data.
* This function will store the new scroll data and update the focus state and
* hit-testing tree.
*/
void UpdateScrollDataAndTreeState(LayersId aRootLayerTreeId,
LayersId aOriginatingLayersId,
const wr::Epoch& aEpoch,
WebRenderScrollData&& aScrollData);
/**
* This is called in the WR-enabled case when we get an empty transaction that
* has some scroll offset updates (from paint-skipped scrolling on the content
* side). This function will update the stored scroll offsets and the
* hit-testing tree.
*/
void UpdateScrollOffsets(LayersId aRootLayerTreeId,
LayersId aOriginatingLayersId,
ScrollUpdatesMap&& aUpdates,
uint32_t aPaintSequenceNumber);
void NotifyLayerTreeAdopted(LayersId aLayersId,
const RefPtr<APZUpdater>& aOldUpdater);
void NotifyLayerTreeRemoved(LayersId aLayersId);
bool GetAPZTestData(LayersId aLayersId, APZTestData* aOutData);
void SetTestAsyncScrollOffset(LayersId aLayersId,
const ScrollableLayerGuid::ViewID& aScrollId,
const CSSPoint& aOffset);
void SetTestAsyncZoom(LayersId aLayersId,
const ScrollableLayerGuid::ViewID& aScrollId,
const LayerToParentLayerScale& aZoom);
// This can only be called on the updater thread.
const WebRenderScrollData* GetScrollData(LayersId aLayersId) const;
/**
* This can be used to assert that the current thread is the
* updater thread (which samples the async transform).
* This does nothing if thread assertions are disabled.
*/
void AssertOnUpdaterThread() const;
/**
* Runs the given task on the APZ "updater thread" for this APZUpdater. If
* this function is called from the updater thread itself then the task is
* run immediately without getting queued.
*
* The layers id argument should be the id of the layer tree that is
* requesting this task to be run. Conceptually each layer tree has a separate
* task queue, so that if one layer tree is blocked waiting for a scene build
* then tasks for the other layer trees can still be processed.
*/
void RunOnUpdaterThread(LayersId aLayersId, already_AddRefed<Runnable> aTask);
/**
* Returns true if currently on the APZUpdater's "updater thread".
*/
bool IsUpdaterThread() const;
/**
* Dispatches the given task to the APZ "controller thread", but does it
* *from* the updater thread. That is, if the thread on which this function is
* called is not the updater thread, the task is first dispatched to the
* updater thread. When the updater thread runs it (or if this is called
* directly on the updater thread), that is when the task gets dispatched to
* the controller thread. The controller thread then actually runs the task.
*
* See the RunOnUpdaterThread method for details on the layers id argument.
*/
void RunOnControllerThread(LayersId aLayersId,
already_AddRefed<Runnable> aTask);
void MarkAsDetached(LayersId aLayersId);
protected:
virtual ~APZUpdater();
// Return true if the APZUpdater is connected to WebRender and is
// using a WebRender scene builder thread as its updater thread.
// This is only false during GTests, and a shutdown codepath during
// which we create a dummy APZUpdater.
bool IsConnectedToWebRender() const;
static already_AddRefed<APZUpdater> GetUpdater(
const wr::WrWindowId& aWindowId);
void ProcessQueue();
private:
RefPtr<APZCTreeManager> mApz;
bool mDestroyed;
bool mConnectedToWebRender;
// Map from layers id to WebRenderScrollData. This can only be touched on
// the updater thread.
std::unordered_map<LayersId, WebRenderScrollData, LayersId::HashFn>
mScrollData;
// Stores epoch state for a particular layers id. This structure is only
// accessed on the updater thread.
struct EpochState {
// The epoch for the most recent scroll data sent from the content side.
wr::Epoch mRequired;
// The epoch for the most recent scene built and swapped in on the WR side.
Maybe<wr::Epoch> mBuilt;
// True if and only if the layers id is the root layers id for the
// compositor
bool mIsRoot;
EpochState();
// Whether or not the state for this layers id is such that it blocks
// processing of tasks for the layer tree. This happens if the root layers
// id or a "visible" layers id has scroll data for an epoch newer than what
// has been built. A "visible" layers id is one that is attached to the full
// layer tree (i.e. there is a chain of reflayer items from the root layer
// tree to the relevant layer subtree). This is not always the case; for
// instance a content process may send the compositor layers for a document
// before the chrome has attached the remote iframe to the root document.
// Since WR only builds pipelines for "visible" layers ids, |mBuilt| being
// populated means that the layers id is "visible".
bool IsBlocked() const;
};
// Map from layers id to epoch state.
// This data structure can only be touched on the updater thread.
std::unordered_map<LayersId, EpochState, LayersId::HashFn> mEpochData;
// Used to manage the mapping from a WR window id to APZUpdater. These are
// only used if WebRender is enabled. Both sWindowIdMap and mWindowId should
// only be used while holding the sWindowIdLock. Note that we use a
// StaticAutoPtr wrapper on sWindowIdMap to avoid a static initializer for the
// unordered_map. This also avoids the initializer/memory allocation in cases
// where we're not using WebRender.
static StaticMutex sWindowIdLock MOZ_UNANNOTATED;
static StaticAutoPtr<std::unordered_map<uint64_t, APZUpdater*>> sWindowIdMap;
Maybe<wr::WrWindowId> mWindowId;
// Lock used to protected mUpdaterThreadId;
mutable Mutex mThreadIdLock MOZ_UNANNOTATED;
// If WebRender and async scene building are enabled, this holds the thread id
// of the scene builder thread (which is the updater thread) for the
// compositor associated with this APZUpdater instance. It may be populated
// even if async scene building is not enabled, but in that case we don't
// care about the contents.
Maybe<PlatformThreadId> mUpdaterThreadId;
// Helper struct that pairs each queued runnable with the layers id that it is
// associated with. This allows us to easily implement the conceptual
// separation of mUpdaterQueue into independent queues per layers id.
struct QueuedTask {
LayersId mLayersId;
RefPtr<Runnable> mRunnable;
};
// Lock used to protect mUpdaterQueue
Mutex mQueueLock MOZ_UNANNOTATED;
// Holds a queue of tasks to be run on the updater thread, when the updater
// thread is a WebRender thread, since it won't have a message loop we can
// dispatch to. Note that although this is a single queue it is conceptually
// separated into multiple ones, one per layers id. Tasks for a given layers
// id will always run in FIFO order, but there is no guaranteed ordering for
// tasks with different layers ids.
std::deque<QueuedTask> mUpdaterQueue;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_APZUpdater_h
|