Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/layers/APZSampler.h"
8 :
9 : #include "APZCTreeManager.h"
10 : #include "AsyncPanZoomController.h"
11 : #include "mozilla/ClearOnShutdown.h"
12 : #include "mozilla/layers/APZThreadUtils.h"
13 : #include "mozilla/layers/CompositorThread.h"
14 : #include "mozilla/layers/LayerMetricsWrapper.h"
15 : #include "mozilla/layers/SynchronousTask.h"
16 : #include "TreeTraversal.h"
17 : #include "mozilla/webrender/WebRenderAPI.h"
18 :
19 : namespace mozilla {
20 : namespace layers {
21 :
22 0 : StaticMutex APZSampler::sWindowIdLock;
23 0 : StaticAutoPtr<std::unordered_map<uint64_t, APZSampler*>> APZSampler::sWindowIdMap;
24 :
25 :
26 0 : APZSampler::APZSampler(const RefPtr<APZCTreeManager>& aApz,
27 0 : bool aIsUsingWebRender)
28 : : mApz(aApz)
29 : , mIsUsingWebRender(aIsUsingWebRender)
30 : , mThreadIdLock("APZSampler::mThreadIdLock")
31 0 : , mSampleTimeLock("APZSampler::mSampleTimeLock")
32 : {
33 0 : MOZ_ASSERT(aApz);
34 0 : mApz->SetSampler(this);
35 0 : }
36 :
37 0 : APZSampler::~APZSampler()
38 : {
39 0 : mApz->SetSampler(nullptr);
40 :
41 0 : StaticMutexAutoLock lock(sWindowIdLock);
42 0 : if (mWindowId) {
43 0 : MOZ_ASSERT(sWindowIdMap);
44 0 : sWindowIdMap->erase(wr::AsUint64(*mWindowId));
45 : }
46 0 : }
47 :
48 : void
49 0 : APZSampler::SetWebRenderWindowId(const wr::WindowId& aWindowId)
50 : {
51 0 : StaticMutexAutoLock lock(sWindowIdLock);
52 0 : MOZ_ASSERT(!mWindowId);
53 0 : mWindowId = Some(aWindowId);
54 0 : if (!sWindowIdMap) {
55 0 : sWindowIdMap = new std::unordered_map<uint64_t, APZSampler*>();
56 0 : NS_DispatchToMainThread(
57 0 : NS_NewRunnableFunction("APZUpdater::ClearOnShutdown", [] {
58 0 : ClearOnShutdown(&sWindowIdMap);
59 0 : }
60 0 : ));
61 : }
62 0 : (*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
63 0 : }
64 :
65 : /*static*/ void
66 0 : APZSampler::SetSamplerThread(const wr::WrWindowId& aWindowId)
67 : {
68 0 : if (RefPtr<APZSampler> sampler = GetSampler(aWindowId)) {
69 0 : MutexAutoLock lock(sampler->mThreadIdLock);
70 0 : sampler->mSamplerThreadId = Some(PlatformThread::CurrentId());
71 : }
72 0 : }
73 :
74 : /*static*/ void
75 0 : APZSampler::SampleForWebRender(const wr::WrWindowId& aWindowId,
76 : wr::Transaction* aTransaction)
77 : {
78 0 : if (RefPtr<APZSampler> sampler = GetSampler(aWindowId)) {
79 0 : wr::TransactionWrapper txn(aTransaction);
80 0 : sampler->SampleForWebRender(txn);
81 : }
82 0 : }
83 :
84 : void
85 0 : APZSampler::SetSampleTime(const TimeStamp& aSampleTime)
86 : {
87 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
88 0 : MutexAutoLock lock(mSampleTimeLock);
89 0 : mSampleTime = aSampleTime;
90 0 : }
91 :
92 : void
93 0 : APZSampler::SampleForWebRender(wr::TransactionWrapper& aTxn)
94 : {
95 0 : AssertOnSamplerThread();
96 0 : TimeStamp sampleTime;
97 : { // scope lock
98 0 : MutexAutoLock lock(mSampleTimeLock);
99 :
100 : // If mSampleTime is null we're in a startup phase where the
101 : // WebRenderBridgeParent hasn't yet provided us with a sample time.
102 : // If we're that early there probably aren't any APZ animations happening
103 : // anyway, so using Timestamp::Now() should be fine.
104 0 : sampleTime = mSampleTime.IsNull() ? TimeStamp::Now() : mSampleTime;
105 : }
106 0 : mApz->SampleForWebRender(aTxn, sampleTime);
107 0 : }
108 :
109 : bool
110 0 : APZSampler::SampleAnimations(const LayerMetricsWrapper& aLayer,
111 : const TimeStamp& aSampleTime)
112 : {
113 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
114 0 : AssertOnSamplerThread();
115 :
116 : // TODO: eventually we can drop the aLayer argument and just walk the APZ
117 : // tree directly in mApz.
118 :
119 0 : bool activeAnimations = false;
120 :
121 0 : ForEachNodePostOrder<ForwardIterator>(aLayer,
122 0 : [&activeAnimations, &aSampleTime](LayerMetricsWrapper aLayerMetrics)
123 0 : {
124 0 : if (AsyncPanZoomController* apzc = aLayerMetrics.GetApzc()) {
125 0 : apzc->ReportCheckerboard(aSampleTime);
126 0 : activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
127 : }
128 0 : }
129 0 : );
130 :
131 0 : return activeAnimations;
132 : }
133 :
134 : LayerToParentLayerMatrix4x4
135 0 : APZSampler::ComputeTransformForScrollThumb(const LayerToParentLayerMatrix4x4& aCurrentTransform,
136 : const LayerMetricsWrapper& aContent,
137 : const ScrollbarData& aThumbData,
138 : bool aScrollbarIsDescendant,
139 : AsyncTransformComponentMatrix* aOutClipTransform)
140 : {
141 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
142 0 : AssertOnSamplerThread();
143 :
144 0 : return mApz->ComputeTransformForScrollThumb(aCurrentTransform,
145 0 : aContent.GetTransform(),
146 : aContent.GetApzc(),
147 : aContent.Metrics(),
148 : aThumbData,
149 : aScrollbarIsDescendant,
150 0 : aOutClipTransform);
151 : }
152 :
153 : CSSRect
154 0 : APZSampler::GetCurrentAsyncLayoutViewport(const LayerMetricsWrapper& aLayer)
155 : {
156 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
157 0 : AssertOnSamplerThread();
158 :
159 0 : MOZ_ASSERT(aLayer.GetApzc());
160 0 : return aLayer.GetApzc()->GetCurrentAsyncLayoutViewport(AsyncPanZoomController::eForCompositing);
161 : }
162 :
163 : ParentLayerPoint
164 0 : APZSampler::GetCurrentAsyncScrollOffset(const LayerMetricsWrapper& aLayer)
165 : {
166 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
167 0 : AssertOnSamplerThread();
168 :
169 0 : MOZ_ASSERT(aLayer.GetApzc());
170 0 : return aLayer.GetApzc()->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForCompositing);
171 : }
172 :
173 : AsyncTransform
174 0 : APZSampler::GetCurrentAsyncTransform(const LayerMetricsWrapper& aLayer)
175 : {
176 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
177 0 : AssertOnSamplerThread();
178 :
179 0 : MOZ_ASSERT(aLayer.GetApzc());
180 0 : return aLayer.GetApzc()->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing);
181 : }
182 :
183 : AsyncTransformComponentMatrix
184 0 : APZSampler::GetOverscrollTransform(const LayerMetricsWrapper& aLayer)
185 : {
186 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
187 0 : AssertOnSamplerThread();
188 :
189 0 : MOZ_ASSERT(aLayer.GetApzc());
190 0 : return aLayer.GetApzc()->GetOverscrollTransform(AsyncPanZoomController::eForCompositing);
191 : }
192 :
193 : AsyncTransformComponentMatrix
194 0 : APZSampler::GetCurrentAsyncTransformWithOverscroll(const LayerMetricsWrapper& aLayer)
195 : {
196 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
197 0 : AssertOnSamplerThread();
198 :
199 0 : MOZ_ASSERT(aLayer.GetApzc());
200 0 : return aLayer.GetApzc()->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForCompositing);
201 : }
202 :
203 : void
204 1 : APZSampler::MarkAsyncTransformAppliedToContent(const LayerMetricsWrapper& aLayer)
205 : {
206 1 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
207 1 : AssertOnSamplerThread();
208 :
209 1 : MOZ_ASSERT(aLayer.GetApzc());
210 16 : aLayer.GetApzc()->MarkAsyncTransformAppliedToContent();
211 1 : }
212 :
213 : bool
214 0 : APZSampler::HasUnusedAsyncTransform(const LayerMetricsWrapper& aLayer)
215 : {
216 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
217 0 : AssertOnSamplerThread();
218 :
219 0 : AsyncPanZoomController* apzc = aLayer.GetApzc();
220 : return apzc
221 0 : && !apzc->GetAsyncTransformAppliedToContent()
222 0 : && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing)).IsIdentity();
223 : }
224 :
225 : void
226 0 : APZSampler::AssertOnSamplerThread() const
227 : {
228 48 : if (APZThreadUtils::GetThreadAssertionsEnabled()) {
229 48 : MOZ_ASSERT(IsSamplerThread());
230 : }
231 1 : }
232 :
233 : bool
234 0 : APZSampler::IsSamplerThread() const
235 : {
236 48 : if (mIsUsingWebRender) {
237 : // If the sampler thread id isn't set yet then we cannot be running on the
238 : // sampler thread (because we will have the thread id before we run any
239 : // other C++ code on it, and this function is only ever invoked from C++
240 : // code), so return false in that scenario.
241 0 : MutexAutoLock lock(mThreadIdLock);
242 0 : return mSamplerThreadId && PlatformThread::CurrentId() == *mSamplerThreadId;
243 : }
244 1 : return CompositorThreadHolder::IsInCompositorThread();
245 : }
246 :
247 : /*static*/ already_AddRefed<APZSampler>
248 0 : APZSampler::GetSampler(const wr::WrWindowId& aWindowId)
249 : {
250 0 : RefPtr<APZSampler> sampler;
251 0 : StaticMutexAutoLock lock(sWindowIdLock);
252 0 : if (sWindowIdMap) {
253 0 : auto it = sWindowIdMap->find(wr::AsUint64(aWindowId));
254 0 : if (it != sWindowIdMap->end()) {
255 0 : sampler = it->second;
256 : }
257 : }
258 0 : return sampler.forget();
259 : }
260 :
261 : } // namespace layers
262 : } // namespace mozilla
263 :
264 : void
265 0 : apz_register_sampler(mozilla::wr::WrWindowId aWindowId)
266 : {
267 0 : mozilla::layers::APZSampler::SetSamplerThread(aWindowId);
268 0 : }
269 :
270 : void
271 : apz_sample_transforms(mozilla::wr::WrWindowId aWindowId,
272 : mozilla::wr::Transaction *aTransaction)
273 : {
274 : mozilla::layers::APZSampler::SampleForWebRender(aWindowId, aTransaction);
275 : }
276 :
277 : void
278 : apz_deregister_sampler(mozilla::wr::WrWindowId aWindowId)
279 : {
280 : }
|