/src/mozilla-central/gfx/layers/ipc/LayerTransactionParent.cpp
Line | Count | Source (jump to first uncovered line) |
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 "LayerTransactionParent.h" |
8 | | #include <vector> // for vector |
9 | | #include "CompositableHost.h" // for CompositableParent, Get, etc |
10 | | #include "ImageLayers.h" // for ImageLayer |
11 | | #include "Layers.h" // for Layer, ContainerLayer, etc |
12 | | #include "CompositableTransactionParent.h" // for EditReplyVector |
13 | | #include "CompositorBridgeParent.h" |
14 | | #include "gfxPrefs.h" |
15 | | #include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D |
16 | | #include "mozilla/layers/AnimationHelper.h" // for GetAnimatedPropValue |
17 | | #include "mozilla/layers/CanvasLayerComposite.h" |
18 | | #include "mozilla/layers/ColorLayerComposite.h" |
19 | | #include "mozilla/layers/Compositor.h" // for Compositor |
20 | | #include "mozilla/layers/ContainerLayerComposite.h" |
21 | | #include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent |
22 | | #include "mozilla/layers/ImageLayerComposite.h" |
23 | | #include "mozilla/layers/LayerManagerComposite.h" |
24 | | #include "mozilla/layers/LayersMessages.h" // for EditReply, etc |
25 | | #include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG |
26 | | #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL |
27 | | #include "mozilla/layers/PaintedLayerComposite.h" |
28 | | #include "mozilla/mozalloc.h" // for operator delete, etc |
29 | | #include "mozilla/Telemetry.h" |
30 | | #include "mozilla/Unused.h" |
31 | | #include "nsCoord.h" // for NSAppUnitsToFloatPixels |
32 | | #include "nsISupportsImpl.h" // for Layer::Release, etc |
33 | | #include "nsLayoutUtils.h" // for nsLayoutUtils |
34 | | #include "nsMathUtils.h" // for NS_round |
35 | | #include "nsPoint.h" // for nsPoint |
36 | | #include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc |
37 | | #include "TreeTraversal.h" // for ForEachNode |
38 | | #include "GeckoProfiler.h" |
39 | | #include "mozilla/layers/TextureHost.h" |
40 | | #include "mozilla/layers/AsyncCompositionManager.h" |
41 | | |
42 | | using mozilla::layout::RenderFrameParent; |
43 | | |
44 | | namespace mozilla { |
45 | | namespace layers { |
46 | | |
47 | | //-------------------------------------------------- |
48 | | // LayerTransactionParent |
49 | | LayerTransactionParent::LayerTransactionParent(HostLayerManager* aManager, |
50 | | CompositorBridgeParentBase* aBridge, |
51 | | CompositorAnimationStorage* aAnimStorage, |
52 | | LayersId aId, |
53 | | TimeDuration aVsyncRate) |
54 | | : mLayerManager(aManager) |
55 | | , mCompositorBridge(aBridge) |
56 | | , mAnimStorage(aAnimStorage) |
57 | | , mId(aId) |
58 | | , mChildEpoch{0} |
59 | | , mParentEpoch{0} |
60 | | , mVsyncRate(aVsyncRate) |
61 | | , mPendingTransaction{0} |
62 | | , mDestroyed(false) |
63 | | , mIPCOpen(false) |
64 | | , mUpdateHitTestingTree(false) |
65 | 0 | { |
66 | 0 | MOZ_ASSERT(mId.IsValid()); |
67 | 0 | } |
68 | | |
69 | | LayerTransactionParent::~LayerTransactionParent() |
70 | 0 | { |
71 | 0 | } |
72 | | |
73 | | void |
74 | | LayerTransactionParent::SetLayerManager(HostLayerManager* aLayerManager, CompositorAnimationStorage* aAnimStorage) |
75 | 0 | { |
76 | 0 | if (mDestroyed) { |
77 | 0 | return; |
78 | 0 | } |
79 | 0 | mLayerManager = aLayerManager; |
80 | 0 | for (auto iter = mLayerMap.Iter(); !iter.Done(); iter.Next()) { |
81 | 0 | auto layer = iter.Data(); |
82 | 0 | if (mAnimStorage && |
83 | 0 | layer->GetCompositorAnimationsId()) { |
84 | 0 | mAnimStorage->ClearById(layer->GetCompositorAnimationsId()); |
85 | 0 | } |
86 | 0 | layer->AsHostLayer()->SetLayerManager(aLayerManager); |
87 | 0 | } |
88 | 0 | mAnimStorage = aAnimStorage; |
89 | 0 | } |
90 | | |
91 | | mozilla::ipc::IPCResult |
92 | | LayerTransactionParent::RecvShutdown() |
93 | 0 | { |
94 | 0 | Destroy(); |
95 | 0 | IProtocol* mgr = Manager(); |
96 | 0 | if (!Send__delete__(this)) { |
97 | 0 | return IPC_FAIL_NO_REASON(mgr); |
98 | 0 | } |
99 | 0 | return IPC_OK(); |
100 | 0 | } |
101 | | |
102 | | mozilla::ipc::IPCResult |
103 | | LayerTransactionParent::RecvShutdownSync() |
104 | 0 | { |
105 | 0 | return RecvShutdown(); |
106 | 0 | } |
107 | | |
108 | | void |
109 | | LayerTransactionParent::Destroy() |
110 | 0 | { |
111 | 0 | if (mDestroyed) { |
112 | 0 | return; |
113 | 0 | } |
114 | 0 | mDestroyed = true; |
115 | 0 | if (mAnimStorage) { |
116 | 0 | for (auto iter = mLayerMap.Iter(); !iter.Done(); iter.Next()) { |
117 | 0 | auto layer = iter.Data(); |
118 | 0 | if (layer->GetCompositorAnimationsId()) { |
119 | 0 | mAnimStorage->ClearById(layer->GetCompositorAnimationsId()); |
120 | 0 | } |
121 | 0 | layer->Disconnect(); |
122 | 0 | } |
123 | 0 | } |
124 | 0 | mCompositables.clear(); |
125 | 0 | mAnimStorage = nullptr; |
126 | 0 | } |
127 | | |
128 | | class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender |
129 | | { |
130 | | public: |
131 | | explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction, |
132 | | const InfallibleTArray<OpDestroy>* aDestroyActors = nullptr) |
133 | | : mLayerTransaction(aLayerTransaction) |
134 | | , mActorsToDestroy(aDestroyActors) |
135 | 0 | { |
136 | 0 | mLayerTransaction->SetAboutToSendAsyncMessages(); |
137 | 0 | } |
138 | | |
139 | | ~AutoLayerTransactionParentAsyncMessageSender() |
140 | 0 | { |
141 | 0 | mLayerTransaction->SendPendingAsyncMessages(); |
142 | 0 | if (mActorsToDestroy) { |
143 | 0 | // Destroy the actors after sending the async messages because the latter may contain |
144 | 0 | // references to some actors. |
145 | 0 | for (const auto& op : *mActorsToDestroy) { |
146 | 0 | mLayerTransaction->DestroyActor(op); |
147 | 0 | } |
148 | 0 | } |
149 | 0 | } |
150 | | private: |
151 | | LayerTransactionParent* mLayerTransaction; |
152 | | const InfallibleTArray<OpDestroy>* mActorsToDestroy; |
153 | | }; |
154 | | |
155 | | mozilla::ipc::IPCResult |
156 | | LayerTransactionParent::RecvPaintTime(const TransactionId& aTransactionId, |
157 | | const TimeDuration& aPaintTime) |
158 | 0 | { |
159 | 0 | mCompositorBridge->UpdatePaintTime(this, aPaintTime); |
160 | 0 | return IPC_OK(); |
161 | 0 | } |
162 | | |
163 | | mozilla::ipc::IPCResult |
164 | | LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) |
165 | 0 | { |
166 | 0 | auto guard = MakeScopeExit([&] { |
167 | 0 | if (recordreplay::IsRecordingOrReplaying()) { |
168 | 0 | recordreplay::child::NotifyPaintComplete(); |
169 | 0 | } |
170 | 0 | }); |
171 | 0 |
|
172 | 0 | AUTO_PROFILER_TRACING("Paint", "LayerTransaction"); |
173 | 0 | AUTO_PROFILER_LABEL("LayerTransactionParent::RecvUpdate", GRAPHICS); |
174 | 0 |
|
175 | 0 | TimeStamp updateStart = TimeStamp::Now(); |
176 | 0 |
|
177 | 0 | MOZ_LAYERS_LOG(("[ParentSide] received txn with %zu edits", aInfo.cset().Length())); |
178 | 0 |
|
179 | 0 | UpdateFwdTransactionId(aInfo.fwdTransactionId()); |
180 | 0 |
|
181 | 0 | if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { |
182 | 0 | for (const auto& op : aInfo.toDestroy()) { |
183 | 0 | DestroyActor(op); |
184 | 0 | } |
185 | 0 | return IPC_OK(); |
186 | 0 | } |
187 | 0 |
|
188 | 0 | // This ensures that destroy operations are always processed. It is not safe |
189 | 0 | // to early-return from RecvUpdate without doing so. |
190 | 0 | AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this, &aInfo.toDestroy()); |
191 | 0 |
|
192 | 0 | { |
193 | 0 | AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this)); |
194 | 0 | mLayerManager->BeginTransaction(); |
195 | 0 | } |
196 | 0 |
|
197 | 0 | // Not all edits require an update to the hit testing tree. |
198 | 0 | mUpdateHitTestingTree = false; |
199 | 0 |
|
200 | 0 | for (EditArray::index_type i = 0; i < aInfo.cset().Length(); ++i) { |
201 | 0 | const Edit& edit = const_cast<Edit&>(aInfo.cset()[i]); |
202 | 0 |
|
203 | 0 | switch (edit.type()) { |
204 | 0 | // Create* ops |
205 | 0 | case Edit::TOpCreatePaintedLayer: { |
206 | 0 | MOZ_LAYERS_LOG(("[ParentSide] CreatePaintedLayer")); |
207 | 0 |
|
208 | 0 | RefPtr<PaintedLayer> layer = mLayerManager->CreatePaintedLayer(); |
209 | 0 | if (!BindLayer(layer, edit.get_OpCreatePaintedLayer())) { |
210 | 0 | return IPC_FAIL_NO_REASON(this); |
211 | 0 | } |
212 | 0 |
|
213 | 0 | UpdateHitTestingTree(layer, "CreatePaintedLayer"); |
214 | 0 | break; |
215 | 0 | } |
216 | 0 | case Edit::TOpCreateContainerLayer: { |
217 | 0 | MOZ_LAYERS_LOG(("[ParentSide] CreateContainerLayer")); |
218 | 0 |
|
219 | 0 | RefPtr<ContainerLayer> layer = mLayerManager->CreateContainerLayer(); |
220 | 0 | if (!BindLayer(layer, edit.get_OpCreateContainerLayer())) { |
221 | 0 | return IPC_FAIL_NO_REASON(this); |
222 | 0 | } |
223 | 0 |
|
224 | 0 | UpdateHitTestingTree(layer, "CreateContainerLayer"); |
225 | 0 | break; |
226 | 0 | } |
227 | 0 | case Edit::TOpCreateImageLayer: { |
228 | 0 | MOZ_LAYERS_LOG(("[ParentSide] CreateImageLayer")); |
229 | 0 |
|
230 | 0 | RefPtr<ImageLayer> layer = mLayerManager->CreateImageLayer(); |
231 | 0 | if (!BindLayer(layer, edit.get_OpCreateImageLayer())) { |
232 | 0 | return IPC_FAIL_NO_REASON(this); |
233 | 0 | } |
234 | 0 |
|
235 | 0 | UpdateHitTestingTree(layer, "CreateImageLayer"); |
236 | 0 | break; |
237 | 0 | } |
238 | 0 | case Edit::TOpCreateColorLayer: { |
239 | 0 | MOZ_LAYERS_LOG(("[ParentSide] CreateColorLayer")); |
240 | 0 |
|
241 | 0 | RefPtr<ColorLayer> layer = mLayerManager->CreateColorLayer(); |
242 | 0 | if (!BindLayer(layer, edit.get_OpCreateColorLayer())) { |
243 | 0 | return IPC_FAIL_NO_REASON(this); |
244 | 0 | } |
245 | 0 |
|
246 | 0 | UpdateHitTestingTree(layer, "CreateColorLayer"); |
247 | 0 | break; |
248 | 0 | } |
249 | 0 | case Edit::TOpCreateCanvasLayer: { |
250 | 0 | MOZ_LAYERS_LOG(("[ParentSide] CreateCanvasLayer")); |
251 | 0 |
|
252 | 0 | RefPtr<CanvasLayer> layer = mLayerManager->CreateCanvasLayer(); |
253 | 0 | if (!BindLayer(layer, edit.get_OpCreateCanvasLayer())) { |
254 | 0 | return IPC_FAIL_NO_REASON(this); |
255 | 0 | } |
256 | 0 |
|
257 | 0 | UpdateHitTestingTree(layer, "CreateCanvasLayer"); |
258 | 0 | break; |
259 | 0 | } |
260 | 0 | case Edit::TOpCreateRefLayer: { |
261 | 0 | MOZ_LAYERS_LOG(("[ParentSide] CreateRefLayer")); |
262 | 0 |
|
263 | 0 | RefPtr<RefLayer> layer = mLayerManager->CreateRefLayer(); |
264 | 0 | if (!BindLayer(layer, edit.get_OpCreateRefLayer())) { |
265 | 0 | return IPC_FAIL_NO_REASON(this); |
266 | 0 | } |
267 | 0 |
|
268 | 0 | UpdateHitTestingTree(layer, "CreateRefLayer"); |
269 | 0 | break; |
270 | 0 | } |
271 | 0 | case Edit::TOpSetDiagnosticTypes: { |
272 | 0 | mLayerManager->SetDiagnosticTypes(edit.get_OpSetDiagnosticTypes().diagnostics()); |
273 | 0 | break; |
274 | 0 | } |
275 | 0 | case Edit::TOpWindowOverlayChanged: { |
276 | 0 | mLayerManager->SetWindowOverlayChanged(); |
277 | 0 | break; |
278 | 0 | } |
279 | 0 | // Tree ops |
280 | 0 | case Edit::TOpSetRoot: { |
281 | 0 | MOZ_LAYERS_LOG(("[ParentSide] SetRoot")); |
282 | 0 |
|
283 | 0 | Layer* newRoot = AsLayer(edit.get_OpSetRoot().root()); |
284 | 0 | if (!newRoot) { |
285 | 0 | return IPC_FAIL_NO_REASON(this); |
286 | 0 | } |
287 | 0 | if (newRoot->GetParent()) { |
288 | 0 | // newRoot is not a root! |
289 | 0 | return IPC_FAIL_NO_REASON(this); |
290 | 0 | } |
291 | 0 | mRoot = newRoot; |
292 | 0 |
|
293 | 0 | UpdateHitTestingTree(mRoot, "SetRoot"); |
294 | 0 | break; |
295 | 0 | } |
296 | 0 | case Edit::TOpInsertAfter: { |
297 | 0 | MOZ_LAYERS_LOG(("[ParentSide] InsertAfter")); |
298 | 0 |
|
299 | 0 | const OpInsertAfter& oia = edit.get_OpInsertAfter(); |
300 | 0 | Layer* child = AsLayer(oia.childLayer()); |
301 | 0 | Layer* layer = AsLayer(oia.container()); |
302 | 0 | Layer* after = AsLayer(oia.after()); |
303 | 0 | if (!child || !layer || !after) { |
304 | 0 | return IPC_FAIL_NO_REASON(this); |
305 | 0 | } |
306 | 0 | ContainerLayer* container = layer->AsContainerLayer(); |
307 | 0 | if (!container || !container->InsertAfter(child, after)) { |
308 | 0 | return IPC_FAIL_NO_REASON(this); |
309 | 0 | } |
310 | 0 |
|
311 | 0 | UpdateHitTestingTree(layer, "InsertAfter"); |
312 | 0 | break; |
313 | 0 | } |
314 | 0 | case Edit::TOpPrependChild: { |
315 | 0 | MOZ_LAYERS_LOG(("[ParentSide] PrependChild")); |
316 | 0 |
|
317 | 0 | const OpPrependChild& oac = edit.get_OpPrependChild(); |
318 | 0 | Layer* child = AsLayer(oac.childLayer()); |
319 | 0 | Layer* layer = AsLayer(oac.container()); |
320 | 0 | if (!child || !layer) { |
321 | 0 | return IPC_FAIL_NO_REASON(this); |
322 | 0 | } |
323 | 0 | ContainerLayer* container = layer->AsContainerLayer(); |
324 | 0 | if (!container || !container->InsertAfter(child, nullptr)) { |
325 | 0 | return IPC_FAIL_NO_REASON(this); |
326 | 0 | } |
327 | 0 |
|
328 | 0 | UpdateHitTestingTree(layer, "PrependChild"); |
329 | 0 | break; |
330 | 0 | } |
331 | 0 | case Edit::TOpRemoveChild: { |
332 | 0 | MOZ_LAYERS_LOG(("[ParentSide] RemoveChild")); |
333 | 0 |
|
334 | 0 | const OpRemoveChild& orc = edit.get_OpRemoveChild(); |
335 | 0 | Layer* childLayer = AsLayer(orc.childLayer()); |
336 | 0 | Layer* layer = AsLayer(orc.container()); |
337 | 0 | if (!childLayer || !layer) { |
338 | 0 | return IPC_FAIL_NO_REASON(this); |
339 | 0 | } |
340 | 0 | ContainerLayer* container = layer->AsContainerLayer(); |
341 | 0 | if (!container || !container->RemoveChild(childLayer)) { |
342 | 0 | return IPC_FAIL_NO_REASON(this); |
343 | 0 | } |
344 | 0 |
|
345 | 0 | UpdateHitTestingTree(layer, "RemoveChild"); |
346 | 0 | break; |
347 | 0 | } |
348 | 0 | case Edit::TOpRepositionChild: { |
349 | 0 | MOZ_LAYERS_LOG(("[ParentSide] RepositionChild")); |
350 | 0 |
|
351 | 0 | const OpRepositionChild& orc = edit.get_OpRepositionChild(); |
352 | 0 | Layer* child = AsLayer(orc.childLayer()); |
353 | 0 | Layer* after = AsLayer(orc.after()); |
354 | 0 | Layer* layer = AsLayer(orc.container()); |
355 | 0 | if (!child || !layer || !after) { |
356 | 0 | return IPC_FAIL_NO_REASON(this); |
357 | 0 | } |
358 | 0 | ContainerLayer* container = layer->AsContainerLayer(); |
359 | 0 | if (!container || !container->RepositionChild(child, after)) { |
360 | 0 | return IPC_FAIL_NO_REASON(this); |
361 | 0 | } |
362 | 0 |
|
363 | 0 | UpdateHitTestingTree(layer, "RepositionChild"); |
364 | 0 | break; |
365 | 0 | } |
366 | 0 | case Edit::TOpRaiseToTopChild: { |
367 | 0 | MOZ_LAYERS_LOG(("[ParentSide] RaiseToTopChild")); |
368 | 0 |
|
369 | 0 | const OpRaiseToTopChild& rtc = edit.get_OpRaiseToTopChild(); |
370 | 0 | Layer* child = AsLayer(rtc.childLayer()); |
371 | 0 | if (!child) { |
372 | 0 | return IPC_FAIL_NO_REASON(this); |
373 | 0 | } |
374 | 0 | Layer* layer = AsLayer(rtc.container()); |
375 | 0 | if (!layer) { |
376 | 0 | return IPC_FAIL_NO_REASON(this); |
377 | 0 | } |
378 | 0 | ContainerLayer* container = layer->AsContainerLayer(); |
379 | 0 | if (!container || !container->RepositionChild(child, nullptr)) { |
380 | 0 | return IPC_FAIL_NO_REASON(this); |
381 | 0 | } |
382 | 0 |
|
383 | 0 | UpdateHitTestingTree(layer, "RaiseToTopChild"); |
384 | 0 | break; |
385 | 0 | } |
386 | 0 | case Edit::TCompositableOperation: { |
387 | 0 | if (!ReceiveCompositableUpdate(edit.get_CompositableOperation())) { |
388 | 0 | return IPC_FAIL_NO_REASON(this); |
389 | 0 | } |
390 | 0 | break; |
391 | 0 | } |
392 | 0 | case Edit::TOpAttachCompositable: { |
393 | 0 | const OpAttachCompositable& op = edit.get_OpAttachCompositable(); |
394 | 0 | RefPtr<CompositableHost> host = FindCompositable(op.compositable()); |
395 | 0 | if (!Attach(AsLayer(op.layer()), host, false)) { |
396 | 0 | return IPC_FAIL_NO_REASON(this); |
397 | 0 | } |
398 | 0 | host->SetCompositorBridgeID(mLayerManager->GetCompositorBridgeID()); |
399 | 0 | break; |
400 | 0 | } |
401 | 0 | case Edit::TOpAttachAsyncCompositable: { |
402 | 0 | const OpAttachAsyncCompositable& op = edit.get_OpAttachAsyncCompositable(); |
403 | 0 | RefPtr<ImageBridgeParent> imageBridge = ImageBridgeParent::GetInstance(OtherPid()); |
404 | 0 | if (!imageBridge) { |
405 | 0 | return IPC_FAIL_NO_REASON(this); |
406 | 0 | } |
407 | 0 | RefPtr<CompositableHost> host = imageBridge->FindCompositable(op.compositable()); |
408 | 0 | if (!host) { |
409 | 0 | // This normally should not happen, but can after a GPU process crash. |
410 | 0 | // Media may not have had time to update the ImageContainer associated |
411 | 0 | // with a video frame, and we may try to attach a stale CompositableHandle. |
412 | 0 | // Rather than break the whole transaction, we just continue. |
413 | 0 | gfxCriticalNote << "CompositableHost " << op.compositable().Value() << " not found"; |
414 | 0 | continue; |
415 | 0 | } |
416 | 0 | if (!Attach(AsLayer(op.layer()), host, true)) { |
417 | 0 | return IPC_FAIL_NO_REASON(this); |
418 | 0 | } |
419 | 0 | host->SetCompositorBridgeID(mLayerManager->GetCompositorBridgeID()); |
420 | 0 | break; |
421 | 0 | } |
422 | 0 | default: |
423 | 0 | MOZ_CRASH("not reached"); |
424 | 0 | } |
425 | 0 | } |
426 | 0 |
|
427 | 0 | // Process simple attribute updates. |
428 | 0 | for (const auto& op : aInfo.setSimpleAttrs()) { |
429 | 0 | MOZ_LAYERS_LOG(("[ParentSide] SetSimpleLayerAttributes")); |
430 | 0 | Layer* layer = AsLayer(op.layer()); |
431 | 0 | if (!layer) { |
432 | 0 | return IPC_FAIL_NO_REASON(this); |
433 | 0 | } |
434 | 0 | const SimpleLayerAttributes& attrs = op.attrs(); |
435 | 0 | const SimpleLayerAttributes& orig = layer->GetSimpleAttributes(); |
436 | 0 | if (!attrs.HitTestingInfoIsEqual(orig)) { |
437 | 0 | UpdateHitTestingTree(layer, "scrolling info changed"); |
438 | 0 | } |
439 | 0 | layer->SetSimpleAttributes(op.attrs()); |
440 | 0 | } |
441 | 0 |
|
442 | 0 | // Process attribute updates. |
443 | 0 | for (const auto& op : aInfo.setAttrs()) { |
444 | 0 | MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes")); |
445 | 0 | if (!SetLayerAttributes(op)) { |
446 | 0 | return IPC_FAIL_NO_REASON(this); |
447 | 0 | } |
448 | 0 | } |
449 | 0 |
|
450 | 0 | // Process paints separately, after all normal edits. |
451 | 0 | for (const auto& op : aInfo.paints()) { |
452 | 0 | if (!ReceiveCompositableUpdate(op)) { |
453 | 0 | return IPC_FAIL_NO_REASON(this); |
454 | 0 | } |
455 | 0 | } |
456 | 0 |
|
457 | 0 | mCompositorBridge->ShadowLayersUpdated(this, aInfo, mUpdateHitTestingTree); |
458 | 0 |
|
459 | 0 | { |
460 | 0 | AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this)); |
461 | 0 | mLayerManager->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW); |
462 | 0 | } |
463 | 0 |
|
464 | 0 | if (!IsSameProcess()) { |
465 | 0 | // Ensure that any pending operations involving back and front |
466 | 0 | // buffers have completed, so that neither process stomps on the |
467 | 0 | // other's buffer contents. |
468 | 0 | LayerManagerComposite::PlatformSyncBeforeReplyUpdate(); |
469 | 0 | } |
470 | 0 |
|
471 | | #ifdef COMPOSITOR_PERFORMANCE_WARNING |
472 | | int compositeTime = (int)(mozilla::TimeStamp::Now() - updateStart).ToMilliseconds(); |
473 | | if (compositeTime > 15) { |
474 | | printf_stderr("Compositor: Layers update took %i ms (blocking gecko).\n", compositeTime); |
475 | | } |
476 | | #endif |
477 | |
|
478 | 0 | // Enable visual warning for long transaction when draw FPS option is enabled |
479 | 0 | bool drawFps = gfxPrefs::LayersDrawFPS(); |
480 | 0 | if (drawFps) { |
481 | 0 | uint32_t visualWarningTrigger = gfxPrefs::LayerTransactionWarning(); |
482 | 0 | // The default theshold is 200ms to trigger, hit red when it take 4 times longer |
483 | 0 | TimeDuration latency = TimeStamp::Now() - aInfo.transactionStart(); |
484 | 0 | if (latency > TimeDuration::FromMilliseconds(visualWarningTrigger)) { |
485 | 0 | float severity = (latency - TimeDuration::FromMilliseconds(visualWarningTrigger)).ToMilliseconds() / |
486 | 0 | (4 * visualWarningTrigger); |
487 | 0 | if (severity > 1.f) { |
488 | 0 | severity = 1.f; |
489 | 0 | } |
490 | 0 | mLayerManager->VisualFrameWarning(severity); |
491 | 0 | printf_stderr("LayerTransactionParent::RecvUpdate transaction from process %d took %f ms", |
492 | 0 | OtherPid(), |
493 | 0 | latency.ToMilliseconds()); |
494 | 0 | } |
495 | 0 |
|
496 | 0 | mLayerManager->RecordUpdateTime((TimeStamp::Now() - updateStart).ToMilliseconds()); |
497 | 0 | } |
498 | 0 |
|
499 | 0 | // Compose after every update when recording/replaying. |
500 | 0 | if (recordreplay::IsRecordingOrReplaying()) { |
501 | 0 | mCompositorBridge->ForceComposeToTarget(nullptr); |
502 | 0 | } |
503 | 0 |
|
504 | 0 | return IPC_OK(); |
505 | 0 | } |
506 | | |
507 | | bool |
508 | | LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp) |
509 | 0 | { |
510 | 0 | Layer* layer = AsLayer(aOp.layer()); |
511 | 0 | if (!layer) { |
512 | 0 | return false; |
513 | 0 | } |
514 | 0 | |
515 | 0 | const LayerAttributes& attrs = aOp.attrs(); |
516 | 0 | const CommonLayerAttributes& common = attrs.common(); |
517 | 0 | if (common.visibleRegion() != layer->GetVisibleRegion()) { |
518 | 0 | UpdateHitTestingTree(layer, "visible region changed"); |
519 | 0 | layer->SetVisibleRegion(common.visibleRegion()); |
520 | 0 | } |
521 | 0 | if (common.eventRegions() != layer->GetEventRegions()) { |
522 | 0 | UpdateHitTestingTree(layer, "event regions changed"); |
523 | 0 | layer->SetEventRegions(common.eventRegions()); |
524 | 0 | } |
525 | 0 | Maybe<ParentLayerIntRect> clipRect = common.useClipRect() ? Some(common.clipRect()) : Nothing(); |
526 | 0 | if (clipRect != layer->GetClipRect()) { |
527 | 0 | UpdateHitTestingTree(layer, "clip rect changed"); |
528 | 0 | layer->SetClipRect(clipRect); |
529 | 0 | } |
530 | 0 | if (LayerHandle maskLayer = common.maskLayer()) { |
531 | 0 | layer->SetMaskLayer(AsLayer(maskLayer)); |
532 | 0 | } else { |
533 | 0 | layer->SetMaskLayer(nullptr); |
534 | 0 | } |
535 | 0 | layer->SetCompositorAnimations(common.compositorAnimations()); |
536 | 0 | // Clean up the Animations by id in the CompositorAnimationStorage |
537 | 0 | // if there are no active animations on the layer |
538 | 0 | if (mAnimStorage && |
539 | 0 | layer->GetCompositorAnimationsId() && |
540 | 0 | layer->GetAnimations().IsEmpty()) { |
541 | 0 | mAnimStorage->ClearById(layer->GetCompositorAnimationsId()); |
542 | 0 | } |
543 | 0 | if (common.scrollMetadata() != layer->GetAllScrollMetadata()) { |
544 | 0 | UpdateHitTestingTree(layer, "scroll metadata changed"); |
545 | 0 | layer->SetScrollMetadata(common.scrollMetadata()); |
546 | 0 | } |
547 | 0 | layer->SetDisplayListLog(common.displayListLog().get()); |
548 | 0 |
|
549 | 0 | // The updated invalid region is added to the existing one, since we can |
550 | 0 | // update multiple times before the next composite. |
551 | 0 | layer->AddInvalidRegion(common.invalidRegion()); |
552 | 0 |
|
553 | 0 | nsTArray<RefPtr<Layer>> maskLayers; |
554 | 0 | for (size_t i = 0; i < common.ancestorMaskLayers().Length(); i++) { |
555 | 0 | Layer* maskLayer = AsLayer(common.ancestorMaskLayers().ElementAt(i)); |
556 | 0 | if (!maskLayer) { |
557 | 0 | return false; |
558 | 0 | } |
559 | 0 | maskLayers.AppendElement(maskLayer); |
560 | 0 | } |
561 | 0 | layer->SetAncestorMaskLayers(maskLayers); |
562 | 0 |
|
563 | 0 | typedef SpecificLayerAttributes Specific; |
564 | 0 | const SpecificLayerAttributes& specific = attrs.specific(); |
565 | 0 | switch (specific.type()) { |
566 | 0 | case Specific::Tnull_t: |
567 | 0 | break; |
568 | 0 |
|
569 | 0 | case Specific::TPaintedLayerAttributes: { |
570 | 0 | MOZ_LAYERS_LOG(("[ParentSide] painted layer")); |
571 | 0 |
|
572 | 0 | PaintedLayer* paintedLayer = layer->AsPaintedLayer(); |
573 | 0 | if (!paintedLayer) { |
574 | 0 | return false; |
575 | 0 | } |
576 | 0 | const PaintedLayerAttributes& attrs = |
577 | 0 | specific.get_PaintedLayerAttributes(); |
578 | 0 |
|
579 | 0 | paintedLayer->SetValidRegion(attrs.validRegion()); |
580 | 0 | break; |
581 | 0 | } |
582 | 0 | case Specific::TContainerLayerAttributes: { |
583 | 0 | MOZ_LAYERS_LOG(("[ParentSide] container layer")); |
584 | 0 |
|
585 | 0 | ContainerLayer* containerLayer = layer->AsContainerLayer(); |
586 | 0 | if (!containerLayer) { |
587 | 0 | return false; |
588 | 0 | } |
589 | 0 | const ContainerLayerAttributes& attrs = |
590 | 0 | specific.get_ContainerLayerAttributes(); |
591 | 0 | containerLayer->SetPreScale(attrs.preXScale(), attrs.preYScale()); |
592 | 0 | containerLayer->SetInheritedScale(attrs.inheritedXScale(), attrs.inheritedYScale()); |
593 | 0 | containerLayer->SetScaleToResolution(attrs.scaleToResolution(), |
594 | 0 | attrs.presShellResolution()); |
595 | 0 | break; |
596 | 0 | } |
597 | 0 | case Specific::TColorLayerAttributes: { |
598 | 0 | MOZ_LAYERS_LOG(("[ParentSide] color layer")); |
599 | 0 |
|
600 | 0 | ColorLayer* colorLayer = layer->AsColorLayer(); |
601 | 0 | if (!colorLayer) { |
602 | 0 | return false; |
603 | 0 | } |
604 | 0 | colorLayer->SetColor(specific.get_ColorLayerAttributes().color().value()); |
605 | 0 | colorLayer->SetBounds(specific.get_ColorLayerAttributes().bounds()); |
606 | 0 | break; |
607 | 0 | } |
608 | 0 | case Specific::TCanvasLayerAttributes: { |
609 | 0 | MOZ_LAYERS_LOG(("[ParentSide] canvas layer")); |
610 | 0 |
|
611 | 0 | CanvasLayer* canvasLayer = layer->AsCanvasLayer(); |
612 | 0 | if (!canvasLayer) { |
613 | 0 | return false; |
614 | 0 | } |
615 | 0 | canvasLayer->SetSamplingFilter(specific.get_CanvasLayerAttributes().samplingFilter()); |
616 | 0 | canvasLayer->SetBounds(specific.get_CanvasLayerAttributes().bounds()); |
617 | 0 | break; |
618 | 0 | } |
619 | 0 | case Specific::TRefLayerAttributes: { |
620 | 0 | MOZ_LAYERS_LOG(("[ParentSide] ref layer")); |
621 | 0 |
|
622 | 0 | RefLayer* refLayer = layer->AsRefLayer(); |
623 | 0 | if (!refLayer) { |
624 | 0 | return false; |
625 | 0 | } |
626 | 0 | refLayer->SetReferentId(specific.get_RefLayerAttributes().id()); |
627 | 0 | refLayer->SetEventRegionsOverride(specific.get_RefLayerAttributes().eventRegionsOverride()); |
628 | 0 | UpdateHitTestingTree(layer, "event regions override changed"); |
629 | 0 | break; |
630 | 0 | } |
631 | 0 | case Specific::TImageLayerAttributes: { |
632 | 0 | MOZ_LAYERS_LOG(("[ParentSide] image layer")); |
633 | 0 |
|
634 | 0 | ImageLayer* imageLayer = layer->AsImageLayer(); |
635 | 0 | if (!imageLayer) { |
636 | 0 | return false; |
637 | 0 | } |
638 | 0 | const ImageLayerAttributes& attrs = specific.get_ImageLayerAttributes(); |
639 | 0 | imageLayer->SetSamplingFilter(attrs.samplingFilter()); |
640 | 0 | imageLayer->SetScaleToSize(attrs.scaleToSize(), attrs.scaleMode()); |
641 | 0 | break; |
642 | 0 | } |
643 | 0 | default: |
644 | 0 | MOZ_CRASH("not reached"); |
645 | 0 | } |
646 | 0 |
|
647 | 0 | return true; |
648 | 0 | } |
649 | | |
650 | | mozilla::ipc::IPCResult |
651 | | LayerTransactionParent::RecvSetLayersObserverEpoch(const LayersObserverEpoch& aChildEpoch) |
652 | 0 | { |
653 | 0 | mChildEpoch = aChildEpoch; |
654 | 0 | return IPC_OK(); |
655 | 0 | } |
656 | | |
657 | | bool |
658 | | LayerTransactionParent::ShouldParentObserveEpoch() |
659 | 0 | { |
660 | 0 | if (mParentEpoch == mChildEpoch) { |
661 | 0 | return false; |
662 | 0 | } |
663 | 0 | |
664 | 0 | mParentEpoch = mChildEpoch; |
665 | 0 | return true; |
666 | 0 | } |
667 | | |
668 | | mozilla::ipc::IPCResult |
669 | | LayerTransactionParent::RecvSetTestSampleTime(const TimeStamp& aTime) |
670 | 0 | { |
671 | 0 | if (!mCompositorBridge->SetTestSampleTime(GetId(), aTime)) { |
672 | 0 | return IPC_FAIL_NO_REASON(this); |
673 | 0 | } |
674 | 0 | return IPC_OK(); |
675 | 0 | } |
676 | | |
677 | | mozilla::ipc::IPCResult |
678 | | LayerTransactionParent::RecvLeaveTestMode() |
679 | 0 | { |
680 | 0 | mCompositorBridge->LeaveTestMode(GetId()); |
681 | 0 | return IPC_OK(); |
682 | 0 | } |
683 | | |
684 | | mozilla::ipc::IPCResult |
685 | | LayerTransactionParent::RecvGetAnimationValue(const uint64_t& aCompositorAnimationsId, |
686 | | OMTAValue* aValue) |
687 | 0 | { |
688 | 0 | if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { |
689 | 0 | return IPC_FAIL_NO_REASON(this); |
690 | 0 | } |
691 | 0 |
|
692 | 0 | // Make sure we apply the latest animation style or else we can end up with |
693 | 0 | // a race between when we temporarily clear the animation transform (in |
694 | 0 | // CompositorBridgeParent::SetShadowProperties) and when animation recalculates |
695 | 0 | // the value. |
696 | 0 | mCompositorBridge->ApplyAsyncProperties( |
697 | 0 | this, CompositorBridgeParentBase::TransformsToSkip::APZ); |
698 | 0 |
|
699 | 0 | if (!mAnimStorage) { |
700 | 0 | return IPC_FAIL_NO_REASON(this); |
701 | 0 | } |
702 | 0 |
|
703 | 0 | *aValue = mAnimStorage->GetOMTAValue(aCompositorAnimationsId); |
704 | 0 | return IPC_OK(); |
705 | 0 | } |
706 | | |
707 | | mozilla::ipc::IPCResult |
708 | | LayerTransactionParent::RecvGetTransform(const LayerHandle& aLayerHandle, |
709 | | MaybeTransform* aTransform) |
710 | 0 | { |
711 | 0 | if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { |
712 | 0 | return IPC_FAIL_NO_REASON(this); |
713 | 0 | } |
714 | 0 |
|
715 | 0 | Layer* layer = AsLayer(aLayerHandle); |
716 | 0 | if (!layer) { |
717 | 0 | return IPC_FAIL_NO_REASON(this); |
718 | 0 | } |
719 | 0 |
|
720 | 0 | mCompositorBridge->ApplyAsyncProperties( |
721 | 0 | this, CompositorBridgeParentBase::TransformsToSkip::NoneOfThem); |
722 | 0 |
|
723 | 0 | Matrix4x4 transform = layer->AsHostLayer()->GetShadowBaseTransform(); |
724 | 0 | // Undo the scale transform applied by FrameTransformToTransformInDevice in |
725 | 0 | // AsyncCompositionManager.cpp. |
726 | 0 | if (ContainerLayer* c = layer->AsContainerLayer()) { |
727 | 0 | transform.PostScale(1.0f/c->GetInheritedXScale(), |
728 | 0 | 1.0f/c->GetInheritedYScale(), |
729 | 0 | 1.0f); |
730 | 0 | } |
731 | 0 | float scale = 1; |
732 | 0 | Point3D scaledOrigin; |
733 | 0 | Point3D transformOrigin; |
734 | 0 | for (uint32_t i = 0; i < layer->GetAnimations().Length(); i++) { |
735 | 0 | if (layer->GetAnimations()[i].data().type() == AnimationData::TTransformData) { |
736 | 0 | const TransformData& data = layer->GetAnimations()[i].data().get_TransformData(); |
737 | 0 | scale = data.appUnitsPerDevPixel(); |
738 | 0 | scaledOrigin = |
739 | 0 | Point3D(NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)), |
740 | 0 | NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)), |
741 | 0 | 0.0f); |
742 | 0 | transformOrigin = data.transformOrigin(); |
743 | 0 | break; |
744 | 0 | } |
745 | 0 | } |
746 | 0 |
|
747 | 0 | // If our parent isn't a perspective layer, then the offset into reference |
748 | 0 | // frame coordinates will have been applied to us. Add an inverse translation |
749 | 0 | // to cancel it out. |
750 | 0 | if (!layer->GetParent() || !layer->GetParent()->GetTransformIsPerspective()) { |
751 | 0 | transform.PostTranslate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z); |
752 | 0 | } |
753 | 0 |
|
754 | 0 | // This function is supposed to include the APZ transform, but if root scroll |
755 | 0 | // containers are enabled, then the APZ transform might not be on |layer| but |
756 | 0 | // instead would be on the parent of |layer|, if that is the root scrollable |
757 | 0 | // metrics. So we special-case that behaviour. |
758 | 0 | if (gfxPrefs::LayoutUseContainersForRootFrames() && |
759 | 0 | !layer->HasScrollableFrameMetrics() && |
760 | 0 | layer->GetParent() && |
761 | 0 | layer->GetParent()->HasRootScrollableFrameMetrics()) { |
762 | 0 | transform *= layer->GetParent()->AsHostLayer()->GetShadowBaseTransform(); |
763 | 0 | } |
764 | 0 |
|
765 | 0 | *aTransform = transform; |
766 | 0 |
|
767 | 0 | return IPC_OK(); |
768 | 0 | } |
769 | | |
770 | | mozilla::ipc::IPCResult |
771 | | LayerTransactionParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollID, |
772 | | const float& aX, const float& aY) |
773 | 0 | { |
774 | 0 | if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { |
775 | 0 | return IPC_FAIL_NO_REASON(this); |
776 | 0 | } |
777 | 0 |
|
778 | 0 | mCompositorBridge->SetTestAsyncScrollOffset(GetId(), aScrollID, CSSPoint(aX, aY)); |
779 | 0 | return IPC_OK(); |
780 | 0 | } |
781 | | |
782 | | mozilla::ipc::IPCResult |
783 | | LayerTransactionParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollID, |
784 | | const float& aValue) |
785 | 0 | { |
786 | 0 | if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) { |
787 | 0 | return IPC_FAIL_NO_REASON(this); |
788 | 0 | } |
789 | 0 |
|
790 | 0 | mCompositorBridge->SetTestAsyncZoom(GetId(), aScrollID, LayerToParentLayerScale(aValue)); |
791 | 0 | return IPC_OK(); |
792 | 0 | } |
793 | | |
794 | | mozilla::ipc::IPCResult |
795 | | LayerTransactionParent::RecvFlushApzRepaints() |
796 | 0 | { |
797 | 0 | mCompositorBridge->FlushApzRepaints(GetId()); |
798 | 0 | return IPC_OK(); |
799 | 0 | } |
800 | | |
801 | | mozilla::ipc::IPCResult |
802 | | LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData) |
803 | 0 | { |
804 | 0 | mCompositorBridge->GetAPZTestData(GetId(), aOutData); |
805 | 0 | return IPC_OK(); |
806 | 0 | } |
807 | | |
808 | | mozilla::ipc::IPCResult |
809 | | LayerTransactionParent::RecvRequestProperty(const nsString& aProperty, float* aValue) |
810 | 0 | { |
811 | 0 | *aValue = -1; |
812 | 0 | return IPC_OK(); |
813 | 0 | } |
814 | | |
815 | | mozilla::ipc::IPCResult |
816 | | LayerTransactionParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId, |
817 | | nsTArray<ScrollableLayerGuid>&& aTargets) |
818 | 0 | { |
819 | 0 | mCompositorBridge->SetConfirmedTargetAPZC(GetId(), aBlockId, aTargets); |
820 | 0 | return IPC_OK(); |
821 | 0 | } |
822 | | |
823 | | bool |
824 | | LayerTransactionParent::Attach(Layer* aLayer, |
825 | | CompositableHost* aCompositable, |
826 | | bool aIsAsync) |
827 | 0 | { |
828 | 0 | if (!aCompositable || !aLayer) { |
829 | 0 | return false; |
830 | 0 | } |
831 | 0 | |
832 | 0 | HostLayer* layer = aLayer->AsHostLayer(); |
833 | 0 | if (!layer) { |
834 | 0 | return false; |
835 | 0 | } |
836 | 0 | |
837 | 0 | TextureSourceProvider* provider = |
838 | 0 | static_cast<HostLayerManager*>(aLayer->Manager())->GetTextureSourceProvider(); |
839 | 0 |
|
840 | 0 | MOZ_ASSERT(!aCompositable->AsWebRenderImageHost()); |
841 | 0 | if (aCompositable->AsWebRenderImageHost()) { |
842 | 0 | gfxCriticalNote << "Use WebRenderImageHost at LayerTransactionParent."; |
843 | 0 | } |
844 | 0 | if (!layer->SetCompositableHost(aCompositable)) { |
845 | 0 | // not all layer types accept a compositable, see bug 967824 |
846 | 0 | return false; |
847 | 0 | } |
848 | 0 | aCompositable->Attach(aLayer, |
849 | 0 | provider, |
850 | 0 | aIsAsync |
851 | 0 | ? CompositableHost::ALLOW_REATTACH |
852 | 0 | | CompositableHost::KEEP_ATTACHED |
853 | 0 | : CompositableHost::NO_FLAGS); |
854 | 0 | return true; |
855 | 0 | } |
856 | | |
857 | | mozilla::ipc::IPCResult |
858 | | LayerTransactionParent::RecvClearCachedResources() |
859 | 0 | { |
860 | 0 | if (mRoot) { |
861 | 0 | // NB: |mRoot| here is the *child* context's root. In this parent |
862 | 0 | // context, it's just a subtree root. We need to scope the clear |
863 | 0 | // of resources to exactly that subtree, so we specify it here. |
864 | 0 | mLayerManager->ClearCachedResources(mRoot); |
865 | 0 | } |
866 | 0 | mCompositorBridge->NotifyClearCachedResources(this); |
867 | 0 | return IPC_OK(); |
868 | 0 | } |
869 | | |
870 | | mozilla::ipc::IPCResult |
871 | | LayerTransactionParent::RecvScheduleComposite() |
872 | 0 | { |
873 | 0 | mCompositorBridge->ScheduleComposite(this); |
874 | 0 | return IPC_OK(); |
875 | 0 | } |
876 | | |
877 | | void |
878 | | LayerTransactionParent::ActorDestroy(ActorDestroyReason why) |
879 | 0 | { |
880 | 0 | Destroy(); |
881 | 0 | } |
882 | | |
883 | | bool |
884 | | LayerTransactionParent::AllocShmem(size_t aSize, |
885 | | ipc::SharedMemory::SharedMemoryType aType, |
886 | | ipc::Shmem* aShmem) |
887 | 0 | { |
888 | 0 | if (!mIPCOpen || mDestroyed) { |
889 | 0 | return false; |
890 | 0 | } |
891 | 0 | return PLayerTransactionParent::AllocShmem(aSize, aType, aShmem); |
892 | 0 | } |
893 | | |
894 | | bool |
895 | | LayerTransactionParent::AllocUnsafeShmem(size_t aSize, |
896 | | ipc::SharedMemory::SharedMemoryType aType, |
897 | | ipc::Shmem* aShmem) |
898 | 0 | { |
899 | 0 | if (!mIPCOpen || mDestroyed) { |
900 | 0 | return false; |
901 | 0 | } |
902 | 0 | |
903 | 0 | return PLayerTransactionParent::AllocUnsafeShmem(aSize, aType, aShmem); |
904 | 0 | } |
905 | | |
906 | | void |
907 | | LayerTransactionParent::DeallocShmem(ipc::Shmem& aShmem) |
908 | 0 | { |
909 | 0 | if (!mIPCOpen || mDestroyed) { |
910 | 0 | return; |
911 | 0 | } |
912 | 0 | PLayerTransactionParent::DeallocShmem(aShmem); |
913 | 0 | } |
914 | | |
915 | | bool LayerTransactionParent::IsSameProcess() const |
916 | 0 | { |
917 | 0 | return OtherPid() == base::GetCurrentProcId(); |
918 | 0 | } |
919 | | |
920 | | TransactionId |
921 | | LayerTransactionParent::FlushTransactionId(TimeStamp& aCompositeEnd) |
922 | 0 | { |
923 | 0 | if (mId.IsValid() && mPendingTransaction.IsValid() && !mVsyncRate.IsZero()) { |
924 | 0 | double latencyMs = (aCompositeEnd - mTxnStartTime).ToMilliseconds(); |
925 | 0 | double latencyNorm = latencyMs / mVsyncRate.ToMilliseconds(); |
926 | 0 | int32_t fracLatencyNorm = lround(latencyNorm * 100.0); |
927 | 0 | Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm); |
928 | 0 | } |
929 | 0 |
|
930 | | #if defined(ENABLE_FRAME_LATENCY_LOG) |
931 | | if (mPendingTransaction.IsValid()) { |
932 | | if (mRefreshStartTime) { |
933 | | int32_t latencyMs = lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds()); |
934 | | printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this); |
935 | | } |
936 | | if (mFwdTime) { |
937 | | int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds()); |
938 | | printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this); |
939 | | } |
940 | | } |
941 | | #endif |
942 | |
|
943 | 0 | mRefreshStartTime = TimeStamp(); |
944 | 0 | mTxnStartTime = TimeStamp(); |
945 | 0 | mFwdTime = TimeStamp(); |
946 | 0 | TransactionId id = mPendingTransaction; |
947 | 0 | mPendingTransaction = TransactionId{0}; |
948 | 0 | return id; |
949 | 0 | } |
950 | | |
951 | | void |
952 | | LayerTransactionParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) |
953 | 0 | { |
954 | 0 | MOZ_ASSERT_UNREACHABLE("unexpected to be called"); |
955 | 0 | } |
956 | | |
957 | | void |
958 | | LayerTransactionParent::SendPendingAsyncMessages() |
959 | 0 | { |
960 | 0 | mCompositorBridge->SendPendingAsyncMessages(); |
961 | 0 | } |
962 | | |
963 | | void |
964 | | LayerTransactionParent::SetAboutToSendAsyncMessages() |
965 | 0 | { |
966 | 0 | mCompositorBridge->SetAboutToSendAsyncMessages(); |
967 | 0 | } |
968 | | |
969 | | void |
970 | | LayerTransactionParent::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) |
971 | 0 | { |
972 | 0 | MOZ_ASSERT_UNREACHABLE("unexpected to be called"); |
973 | 0 | } |
974 | | |
975 | | bool |
976 | | LayerTransactionParent::BindLayerToHandle(RefPtr<Layer> aLayer, const LayerHandle& aHandle) |
977 | 0 | { |
978 | 0 | if (!aHandle || !aLayer) { |
979 | 0 | return false; |
980 | 0 | } |
981 | 0 | if (auto entry = mLayerMap.LookupForAdd(aHandle.Value())) { |
982 | 0 | return false; |
983 | 0 | } else { |
984 | 0 | entry.OrInsert([&aLayer] () { return aLayer; }); |
985 | 0 | } |
986 | 0 | return true; |
987 | 0 | } |
988 | | |
989 | | Layer* |
990 | | LayerTransactionParent::AsLayer(const LayerHandle& aHandle) |
991 | 0 | { |
992 | 0 | if (!aHandle) { |
993 | 0 | return nullptr; |
994 | 0 | } |
995 | 0 | return mLayerMap.GetWeak(aHandle.Value()); |
996 | 0 | } |
997 | | |
998 | | mozilla::ipc::IPCResult |
999 | | LayerTransactionParent::RecvNewCompositable(const CompositableHandle& aHandle, const TextureInfo& aInfo) |
1000 | 0 | { |
1001 | 0 | if (!AddCompositable(aHandle, aInfo, /* aUseWebRender */ false)) { |
1002 | 0 | return IPC_FAIL_NO_REASON(this); |
1003 | 0 | } |
1004 | 0 | return IPC_OK(); |
1005 | 0 | } |
1006 | | |
1007 | | mozilla::ipc::IPCResult |
1008 | | LayerTransactionParent::RecvReleaseLayer(const LayerHandle& aHandle) |
1009 | 0 | { |
1010 | 0 | RefPtr<Layer> layer; |
1011 | 0 | if (!aHandle || !mLayerMap.Remove(aHandle.Value(), getter_AddRefs(layer))) { |
1012 | 0 | return IPC_FAIL_NO_REASON(this); |
1013 | 0 | } |
1014 | 0 | if (mAnimStorage && |
1015 | 0 | layer->GetCompositorAnimationsId()) { |
1016 | 0 | mAnimStorage->ClearById(layer->GetCompositorAnimationsId()); |
1017 | 0 | layer->ClearCompositorAnimations(); |
1018 | 0 | } |
1019 | 0 | layer->Disconnect(); |
1020 | 0 | return IPC_OK(); |
1021 | 0 | } |
1022 | | |
1023 | | mozilla::ipc::IPCResult |
1024 | | LayerTransactionParent::RecvReleaseCompositable(const CompositableHandle& aHandle) |
1025 | 0 | { |
1026 | 0 | ReleaseCompositable(aHandle); |
1027 | 0 | return IPC_OK(); |
1028 | 0 | } |
1029 | | |
1030 | | mozilla::ipc::IPCResult |
1031 | | LayerTransactionParent::RecvRecordPaintTimes(const PaintTiming& aTiming) |
1032 | 0 | { |
1033 | 0 | // Currently we only add paint timings for remote layers. In the future |
1034 | 0 | // we could be smarter and use paint timings from the UI process, either |
1035 | 0 | // as a separate overlay or if no remote layers are attached. |
1036 | 0 | if (mLayerManager && mCompositorBridge->IsRemote()) { |
1037 | 0 | mLayerManager->RecordPaintTimes(aTiming); |
1038 | 0 | } |
1039 | 0 | return IPC_OK(); |
1040 | 0 | } |
1041 | | |
1042 | | mozilla::ipc::IPCResult |
1043 | | LayerTransactionParent::RecvGetTextureFactoryIdentifier(TextureFactoryIdentifier* aIdentifier) |
1044 | 0 | { |
1045 | 0 | if (!mLayerManager) { |
1046 | 0 | // Default constructor sets mParentBackend to LAYERS_NONE. |
1047 | 0 | return IPC_OK(); |
1048 | 0 | } |
1049 | 0 |
|
1050 | 0 | *aIdentifier = mLayerManager->GetTextureFactoryIdentifier(); |
1051 | 0 | return IPC_OK(); |
1052 | 0 | } |
1053 | | |
1054 | | } // namespace layers |
1055 | | } // namespace mozilla |