Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=2 et 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/CompositorBridgeChild.h"
8 : #include "mozilla/layers/CompositorBridgeParent.h"
9 : #include "mozilla/layers/CompositorThread.h"
10 : #include <stddef.h> // for size_t
11 : #include "ClientLayerManager.h" // for ClientLayerManager
12 : #include "base/message_loop.h" // for MessageLoop
13 : #include "base/task.h" // for NewRunnableMethod, etc
14 : #include "gfxPrefs.h"
15 : #include "mozilla/dom/TabGroup.h"
16 : #include "mozilla/layers/CompositorManagerChild.h"
17 : #include "mozilla/layers/ImageBridgeChild.h"
18 : #include "mozilla/layers/APZChild.h"
19 : #include "mozilla/layers/IAPZCTreeManager.h"
20 : #include "mozilla/layers/APZCTreeManagerChild.h"
21 : #include "mozilla/layers/LayerTransactionChild.h"
22 : #include "mozilla/layers/PaintThread.h"
23 : #include "mozilla/layers/PLayerTransactionChild.h"
24 : #include "mozilla/layers/PTextureChild.h"
25 : #include "mozilla/layers/TextureClient.h"// for TextureClient
26 : #include "mozilla/layers/TextureClientPool.h"// for TextureClientPool
27 : #include "mozilla/layers/WebRenderBridgeChild.h"
28 : #include "mozilla/gfx/gfxVars.h"
29 : #include "mozilla/gfx/GPUProcessManager.h"
30 : #include "mozilla/gfx/Logging.h"
31 : #include "mozilla/mozalloc.h" // for operator new, etc
32 : #include "nsAutoPtr.h"
33 : #include "nsDebug.h" // for NS_RUNTIMEABORT
34 : #include "nsIObserver.h" // for nsIObserver
35 : #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
36 : #include "nsTArray.h" // for nsTArray, nsTArray_Impl
37 : #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop, etc
38 : #include "FrameLayerBuilder.h"
39 : #include "mozilla/dom/TabChild.h"
40 : #include "mozilla/dom/TabParent.h"
41 : #include "mozilla/dom/ContentChild.h"
42 : #include "mozilla/Unused.h"
43 : #include "mozilla/DebugOnly.h"
44 : #if defined(XP_WIN)
45 : #include "WinUtils.h"
46 : #endif
47 : #include "mozilla/widget/CompositorWidget.h"
48 : #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
49 : # include "mozilla/widget/CompositorWidgetChild.h"
50 : #endif
51 : #include "VsyncSource.h"
52 :
53 : using mozilla::layers::LayerTransactionChild;
54 : using mozilla::dom::TabChildBase;
55 : using mozilla::Unused;
56 : using mozilla::gfx::GPUProcessManager;
57 :
58 : namespace mozilla {
59 : namespace layers {
60 :
61 : static int sShmemCreationCounter = 0;
62 :
63 29 : static void ResetShmemCounter()
64 : {
65 29 : sShmemCreationCounter = 0;
66 29 : }
67 :
68 1 : static void ShmemAllocated(CompositorBridgeChild* aProtocol)
69 : {
70 1 : sShmemCreationCounter++;
71 1 : if (sShmemCreationCounter > 256) {
72 0 : aProtocol->SendSyncWithCompositor();
73 0 : ResetShmemCounter();
74 0 : MOZ_PERFORMANCE_WARNING("gfx", "The number of shmem allocations is too damn high!");
75 : }
76 1 : }
77 :
78 3 : static StaticRefPtr<CompositorBridgeChild> sCompositorBridge;
79 :
80 : Atomic<int32_t> KnowsCompositor::sSerialCounter(0);
81 :
82 3 : CompositorBridgeChild::CompositorBridgeChild(CompositorManagerChild *aManager)
83 : : mCompositorManager(aManager)
84 : , mIdNamespace(0)
85 : , mResourceId(0)
86 : , mCanSend(false)
87 : , mActorDestroyed(false)
88 : , mFwdTransactionId(0)
89 : , mDeviceResetSequenceNumber(0)
90 3 : , mMessageLoop(MessageLoop::current())
91 : , mProcessToken(0)
92 : , mSectionAllocator(nullptr)
93 : , mPaintLock("CompositorBridgeChild.mPaintLock")
94 : , mOutstandingAsyncPaints(0)
95 6 : , mIsWaitingForPaint(false)
96 : {
97 3 : MOZ_ASSERT(NS_IsMainThread());
98 3 : }
99 :
100 0 : CompositorBridgeChild::~CompositorBridgeChild()
101 : {
102 0 : if (mCanSend) {
103 0 : gfxCriticalError() << "CompositorBridgeChild was not deinitialized";
104 : }
105 0 : }
106 :
107 : bool
108 37 : CompositorBridgeChild::IsSameProcess() const
109 : {
110 37 : return OtherPid() == base::GetCurrentProcId();
111 : }
112 :
113 : void
114 0 : CompositorBridgeChild::AfterDestroy()
115 : {
116 : // Note that we cannot rely upon mCanSend here because we already set that to
117 : // false to prevent normal IPDL calls from being made after SendWillClose.
118 : // The only time we should not issue Send__delete__ is if the actor is already
119 : // destroyed, e.g. the compositor process crashed.
120 0 : if (!mActorDestroyed) {
121 0 : Send__delete__(this);
122 : }
123 :
124 0 : if (sCompositorBridge == this) {
125 0 : sCompositorBridge = nullptr;
126 : }
127 0 : }
128 :
129 : void
130 0 : CompositorBridgeChild::Destroy()
131 : {
132 : // This must not be called from the destructor!
133 0 : mTexturesWaitingRecycled.Clear();
134 :
135 0 : if (!mCanSend) {
136 0 : return;
137 : }
138 :
139 0 : for (size_t i = 0; i < mTexturePools.Length(); i++) {
140 0 : mTexturePools[i]->Destroy();
141 : }
142 :
143 0 : if (mSectionAllocator) {
144 0 : delete mSectionAllocator;
145 0 : mSectionAllocator = nullptr;
146 : }
147 :
148 : // Destroying the layer manager may cause all sorts of things to happen, so
149 : // let's make sure there is still a reference to keep this alive whatever
150 : // happens.
151 0 : RefPtr<CompositorBridgeChild> selfRef = this;
152 :
153 0 : if (mLayerManager) {
154 0 : mLayerManager->Destroy();
155 0 : mLayerManager = nullptr;
156 : }
157 :
158 0 : AutoTArray<PLayerTransactionChild*, 16> transactions;
159 0 : ManagedPLayerTransactionChild(transactions);
160 0 : for (int i = transactions.Length() - 1; i >= 0; --i) {
161 : RefPtr<LayerTransactionChild> layers =
162 0 : static_cast<LayerTransactionChild*>(transactions[i]);
163 0 : layers->Destroy();
164 : }
165 :
166 0 : AutoTArray<PWebRenderBridgeChild*, 16> wrBridges;
167 0 : ManagedPWebRenderBridgeChild(wrBridges);
168 0 : for (int i = wrBridges.Length() - 1; i >= 0; --i) {
169 : RefPtr<WebRenderBridgeChild> wrBridge =
170 0 : static_cast<WebRenderBridgeChild*>(wrBridges[i]);
171 0 : wrBridge->Destroy(/* aIsSync */ false);
172 : }
173 :
174 0 : const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
175 0 : for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
176 0 : RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
177 :
178 0 : if (texture) {
179 0 : texture->Destroy();
180 : }
181 : }
182 :
183 0 : SendWillClose();
184 0 : mCanSend = false;
185 :
186 : // We no longer care about unexpected shutdowns, in the remote process case.
187 0 : mProcessToken = 0;
188 :
189 : // The call just made to SendWillClose can result in IPC from the
190 : // CompositorBridgeParent to the CompositorBridgeChild (e.g. caused by the destruction
191 : // of shared memory). We need to ensure this gets processed by the
192 : // CompositorBridgeChild before it gets destroyed. It suffices to ensure that
193 : // events already in the MessageLoop get processed before the
194 : // CompositorBridgeChild is destroyed, so we add a task to the MessageLoop to
195 : // handle compositor destruction.
196 :
197 : // From now on we can't send any message message.
198 0 : MessageLoop::current()->PostTask(NewRunnableMethod(
199 : "CompositorBridgeChild::AfterDestroy",
200 0 : selfRef, &CompositorBridgeChild::AfterDestroy));
201 : }
202 :
203 : // static
204 : void
205 0 : CompositorBridgeChild::ShutDown()
206 : {
207 0 : if (sCompositorBridge) {
208 0 : sCompositorBridge->Destroy();
209 0 : SpinEventLoopUntil([&]() { return !sCompositorBridge; });
210 : }
211 0 : }
212 :
213 : bool
214 0 : CompositorBridgeChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId,
215 : FrameMetrics& aFrame)
216 : {
217 0 : SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId);
218 0 : if (data) {
219 0 : data->CopyFrameMetrics(&aFrame);
220 0 : return true;
221 : }
222 0 : return false;
223 : }
224 :
225 : void
226 2 : CompositorBridgeChild::InitForContent(uint32_t aNamespace)
227 : {
228 2 : MOZ_ASSERT(NS_IsMainThread());
229 2 : MOZ_ASSERT(aNamespace);
230 :
231 4 : if (RefPtr<CompositorBridgeChild> old = sCompositorBridge.forget()) {
232 : // Note that at this point, ActorDestroy may not have been called yet,
233 : // meaning mCanSend is still true. In this case we will try to send a
234 : // synchronous WillClose message to the parent, and will certainly get
235 : // a false result and a MsgDropped processing error. This is okay.
236 0 : old->Destroy();
237 : }
238 :
239 2 : mCanSend = true;
240 2 : mIdNamespace = aNamespace;
241 2 : sCompositorBridge = this;
242 2 : }
243 :
244 : void
245 1 : CompositorBridgeChild::InitForWidget(uint64_t aProcessToken,
246 : LayerManager* aLayerManager,
247 : uint32_t aNamespace)
248 : {
249 1 : MOZ_ASSERT(NS_IsMainThread());
250 1 : MOZ_ASSERT(aProcessToken);
251 1 : MOZ_ASSERT(aLayerManager);
252 1 : MOZ_ASSERT(aNamespace);
253 :
254 1 : mCanSend = true;
255 1 : mProcessToken = aProcessToken;
256 1 : mLayerManager = aLayerManager;
257 1 : mIdNamespace = aNamespace;
258 1 : }
259 :
260 : /*static*/ CompositorBridgeChild*
261 10 : CompositorBridgeChild::Get()
262 : {
263 : // This is only expected to be used in child processes.
264 10 : MOZ_ASSERT(!XRE_IsParentProcess());
265 10 : return sCompositorBridge;
266 : }
267 :
268 : // static
269 : bool
270 0 : CompositorBridgeChild::ChildProcessHasCompositorBridge()
271 : {
272 0 : return sCompositorBridge != nullptr;
273 : }
274 :
275 : /* static */ bool
276 0 : CompositorBridgeChild::CompositorIsInGPUProcess()
277 : {
278 0 : MOZ_ASSERT(NS_IsMainThread());
279 :
280 0 : if (XRE_IsParentProcess()) {
281 0 : return !!GPUProcessManager::Get()->GetGPUChild();
282 : }
283 :
284 0 : MOZ_ASSERT(XRE_IsContentProcess());
285 0 : CompositorBridgeChild* bridge = CompositorBridgeChild::Get();
286 0 : if (!bridge) {
287 0 : return false;
288 : }
289 :
290 0 : return bridge->OtherPid() != dom::ContentChild::GetSingleton()->OtherPid();
291 : }
292 :
293 : PLayerTransactionChild*
294 2 : CompositorBridgeChild::AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints, const uint64_t& aId)
295 : {
296 2 : LayerTransactionChild* c = new LayerTransactionChild(aId);
297 2 : c->AddIPDLReference();
298 :
299 2 : TabChild* tabChild = TabChild::GetFrom(c->GetId());
300 :
301 : // Do the DOM Labeling.
302 2 : if (tabChild) {
303 : nsCOMPtr<nsIEventTarget> target =
304 2 : tabChild->TabGroup()->EventTargetFor(TaskCategory::Other);
305 1 : SetEventTargetForActor(c, target);
306 1 : MOZ_ASSERT(c->GetActorEventTarget());
307 : }
308 :
309 2 : return c;
310 : }
311 :
312 : bool
313 0 : CompositorBridgeChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor)
314 : {
315 0 : uint64_t childId = static_cast<LayerTransactionChild*>(actor)->GetId();
316 :
317 0 : for (auto iter = mFrameMetricsTable.Iter(); !iter.Done(); iter.Next()) {
318 0 : nsAutoPtr<SharedFrameMetricsData>& data = iter.Data();
319 0 : if (data->GetLayersId() == childId) {
320 0 : iter.Remove();
321 : }
322 : }
323 0 : static_cast<LayerTransactionChild*>(actor)->ReleaseIPDLReference();
324 0 : return true;
325 : }
326 :
327 : mozilla::ipc::IPCResult
328 0 : CompositorBridgeChild::RecvInvalidateLayers(const uint64_t& aLayersId)
329 : {
330 0 : if (mLayerManager) {
331 0 : MOZ_ASSERT(aLayersId == 0);
332 0 : FrameLayerBuilder::InvalidateAllLayers(mLayerManager);
333 0 : } else if (aLayersId != 0) {
334 0 : if (dom::TabChild* child = dom::TabChild::GetFrom(aLayersId)) {
335 0 : child->InvalidateLayers();
336 : }
337 : }
338 0 : return IPC_OK();
339 : }
340 :
341 : #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
342 0 : static void CalculatePluginClip(const LayoutDeviceIntRect& aBounds,
343 : const nsTArray<LayoutDeviceIntRect>& aPluginClipRects,
344 : const LayoutDeviceIntPoint& aContentOffset,
345 : const LayoutDeviceIntRegion& aParentLayerVisibleRegion,
346 : nsTArray<LayoutDeviceIntRect>& aResult,
347 : LayoutDeviceIntRect& aVisibleBounds,
348 : bool& aPluginIsVisible)
349 : {
350 0 : aPluginIsVisible = true;
351 0 : LayoutDeviceIntRegion contentVisibleRegion;
352 : // aPluginClipRects (plugin widget origin) - contains *visible* rects
353 0 : for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) {
354 0 : LayoutDeviceIntRect rect = aPluginClipRects[idx];
355 : // shift to content origin
356 0 : rect.MoveBy(aBounds.x, aBounds.y);
357 : // accumulate visible rects
358 0 : contentVisibleRegion.OrWith(rect);
359 : }
360 : // apply layers clip (window origin)
361 0 : LayoutDeviceIntRegion region = aParentLayerVisibleRegion;
362 0 : region.MoveBy(-aContentOffset.x, -aContentOffset.y);
363 0 : contentVisibleRegion.AndWith(region);
364 0 : if (contentVisibleRegion.IsEmpty()) {
365 0 : aPluginIsVisible = false;
366 0 : return;
367 : }
368 : // shift to plugin widget origin
369 0 : contentVisibleRegion.MoveBy(-aBounds.x, -aBounds.y);
370 0 : for (auto iter = contentVisibleRegion.RectIter(); !iter.Done(); iter.Next()) {
371 0 : const LayoutDeviceIntRect& rect = iter.Get();
372 0 : aResult.AppendElement(rect);
373 0 : aVisibleBounds.UnionRect(aVisibleBounds, rect);
374 : }
375 : }
376 : #endif
377 :
378 : mozilla::ipc::IPCResult
379 0 : CompositorBridgeChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset,
380 : const LayoutDeviceIntRegion& aParentLayerVisibleRegion,
381 : nsTArray<PluginWindowData>&& aPlugins)
382 : {
383 : #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
384 : NS_NOTREACHED("CompositorBridgeChild::RecvUpdatePluginConfigurations calls "
385 : "unexpected on this platform.");
386 : return IPC_FAIL_NO_REASON(this);
387 : #else
388 : // Now that we are on the main thread, update plugin widget config.
389 : // This should happen a little before we paint to the screen assuming
390 : // the main thread is running freely.
391 0 : DebugOnly<nsresult> rv;
392 0 : MOZ_ASSERT(NS_IsMainThread());
393 :
394 : // Tracks visible plugins we update, so we can hide any plugins we don't.
395 0 : nsTArray<uintptr_t> visiblePluginIds;
396 0 : nsIWidget* parent = nullptr;
397 0 : for (uint32_t pluginsIdx = 0; pluginsIdx < aPlugins.Length(); pluginsIdx++) {
398 : nsIWidget* widget =
399 0 : nsIWidget::LookupRegisteredPluginWindow(aPlugins[pluginsIdx].windowId());
400 0 : if (!widget) {
401 0 : NS_WARNING("Unexpected, plugin id not found!");
402 0 : continue;
403 : }
404 0 : if (!parent) {
405 0 : parent = widget->GetParent();
406 : }
407 0 : bool isVisible = aPlugins[pluginsIdx].visible();
408 0 : if (widget && !widget->Destroyed()) {
409 0 : LayoutDeviceIntRect bounds;
410 0 : LayoutDeviceIntRect visibleBounds;
411 : // If the plugin is visible update it's geometry.
412 0 : if (isVisible) {
413 : // Set bounds (content origin)
414 0 : bounds = aPlugins[pluginsIdx].bounds();
415 0 : nsTArray<LayoutDeviceIntRect> rectsOut;
416 : // This call may change the value of isVisible
417 0 : CalculatePluginClip(bounds, aPlugins[pluginsIdx].clip(),
418 : aContentOffset,
419 : aParentLayerVisibleRegion,
420 0 : rectsOut, visibleBounds, isVisible);
421 : // content clipping region (widget origin)
422 0 : rv = widget->SetWindowClipRegion(rectsOut, false);
423 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
424 : // This will trigger a browser window paint event for areas uncovered
425 : // by a child window move, and will call invalidate on the plugin
426 : // parent window which the browser owns. The latter gets picked up in
427 : // our OnPaint handler and forwarded over to the plugin process async.
428 0 : widget->Resize(aContentOffset.x + bounds.x,
429 0 : aContentOffset.y + bounds.y,
430 0 : bounds.width, bounds.height, true);
431 : }
432 :
433 0 : widget->Enable(isVisible);
434 :
435 : // visible state - updated after clipping, prior to invalidating
436 0 : widget->Show(isVisible);
437 :
438 : // Handle invalidation, this can be costly, avoid if it is not needed.
439 0 : if (isVisible) {
440 : // invalidate region (widget origin)
441 : #if defined(XP_WIN)
442 : // Work around for flash's crummy sandbox. See bug 762948. This call
443 : // digs down into the window hirearchy, invalidating regions on
444 : // windows owned by other processes.
445 : mozilla::widget::WinUtils::InvalidatePluginAsWorkaround(
446 : widget, visibleBounds);
447 : #else
448 0 : widget->Invalidate(visibleBounds);
449 : #endif
450 0 : visiblePluginIds.AppendElement(aPlugins[pluginsIdx].windowId());
451 : }
452 : }
453 : }
454 : // Any plugins we didn't update need to be hidden, as they are
455 : // not associated with visible content.
456 0 : nsIWidget::UpdateRegisteredPluginWindowVisibility((uintptr_t)parent, visiblePluginIds);
457 0 : if (!mCanSend) {
458 0 : return IPC_OK();
459 : }
460 0 : SendRemotePluginsReady();
461 0 : return IPC_OK();
462 : #endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
463 : }
464 :
465 : #if defined(XP_WIN)
466 : static void
467 : ScheduleSendAllPluginsCaptured(CompositorBridgeChild* aThis, MessageLoop* aLoop)
468 : {
469 : aLoop->PostTask(NewNonOwningRunnableMethod(
470 : "CompositorBridgeChild::SendAllPluginsCaptured",
471 : aThis, &CompositorBridgeChild::SendAllPluginsCaptured));
472 : }
473 : #endif
474 :
475 : mozilla::ipc::IPCResult
476 0 : CompositorBridgeChild::RecvCaptureAllPlugins(const uintptr_t& aParentWidget)
477 : {
478 : #if defined(XP_WIN)
479 : MOZ_ASSERT(NS_IsMainThread());
480 : nsIWidget::CaptureRegisteredPlugins(aParentWidget);
481 :
482 : // Bounce the call to SendAllPluginsCaptured off the ImageBridgeChild loop,
483 : // to make sure that the image updates on that thread have been processed.
484 : ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
485 : NewRunnableFunction(&ScheduleSendAllPluginsCaptured, this,
486 : MessageLoop::current()));
487 : return IPC_OK();
488 : #else
489 0 : MOZ_ASSERT_UNREACHABLE(
490 : "CompositorBridgeChild::RecvCaptureAllPlugins calls unexpected.");
491 : return IPC_FAIL_NO_REASON(this);
492 : #endif
493 : }
494 :
495 : mozilla::ipc::IPCResult
496 0 : CompositorBridgeChild::RecvHideAllPlugins(const uintptr_t& aParentWidget)
497 : {
498 : #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
499 : NS_NOTREACHED("CompositorBridgeChild::RecvHideAllPlugins calls "
500 : "unexpected on this platform.");
501 : return IPC_FAIL_NO_REASON(this);
502 : #else
503 0 : MOZ_ASSERT(NS_IsMainThread());
504 0 : nsTArray<uintptr_t> list;
505 0 : nsIWidget::UpdateRegisteredPluginWindowVisibility(aParentWidget, list);
506 0 : if (!mCanSend) {
507 0 : return IPC_OK();
508 : }
509 0 : SendRemotePluginsReady();
510 0 : return IPC_OK();
511 : #endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
512 : }
513 :
514 : mozilla::ipc::IPCResult
515 54 : CompositorBridgeChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId,
516 : const TimeStamp& aCompositeStart,
517 : const TimeStamp& aCompositeEnd)
518 : {
519 54 : if (mLayerManager) {
520 27 : MOZ_ASSERT(aId == 0);
521 27 : MOZ_ASSERT(mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT ||
522 : mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR);
523 : // Hold a reference to keep LayerManager alive. See Bug 1242668.
524 54 : RefPtr<LayerManager> m = mLayerManager;
525 27 : m->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
526 27 : } else if (aId != 0) {
527 54 : RefPtr<dom::TabChild> child = dom::TabChild::GetFrom(aId);
528 27 : if (child) {
529 27 : child->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
530 : }
531 : }
532 :
533 54 : for (size_t i = 0; i < mTexturePools.Length(); i++) {
534 0 : mTexturePools[i]->ReturnDeferredClients();
535 : }
536 :
537 54 : return IPC_OK();
538 : }
539 :
540 : void
541 0 : CompositorBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
542 : {
543 0 : if (aWhy == AbnormalShutdown) {
544 : // If the parent side runs into a problem then the actor will be destroyed.
545 : // There is nothing we can do in the child side, here sets mCanSend as false.
546 0 : gfxCriticalNote << "Receive IPC close with reason=AbnormalShutdown";
547 : }
548 :
549 : {
550 : // We take the lock to update these fields, since they are read from the
551 : // paint thread. We don't need the lock to init them, since that happens
552 : // on the main thread before the paint thread can ever grab a reference
553 : // to the CompositorBridge object.
554 : //
555 : // Note that it is useful to take this lock for one other reason: It also
556 : // tells us whether GetIPCChannel is safe to call. If we access the IPC
557 : // channel within this lock, when mCanSend is true, then we know it has not
558 : // been zapped by IPDL.
559 0 : MonitorAutoLock lock(mPaintLock);
560 0 : mCanSend = false;
561 0 : mActorDestroyed = true;
562 : }
563 :
564 0 : if (mProcessToken && XRE_IsParentProcess()) {
565 0 : GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
566 : }
567 0 : }
568 :
569 : mozilla::ipc::IPCResult
570 0 : CompositorBridgeChild::RecvSharedCompositorFrameMetrics(
571 : const mozilla::ipc::SharedMemoryBasic::Handle& metrics,
572 : const CrossProcessMutexHandle& handle,
573 : const uint64_t& aLayersId,
574 : const uint32_t& aAPZCId)
575 : {
576 : SharedFrameMetricsData* data = new SharedFrameMetricsData(
577 0 : metrics, handle, aLayersId, aAPZCId);
578 0 : mFrameMetricsTable.Put(data->GetViewID(), data);
579 0 : return IPC_OK();
580 : }
581 :
582 : mozilla::ipc::IPCResult
583 0 : CompositorBridgeChild::RecvReleaseSharedCompositorFrameMetrics(
584 : const ViewID& aId,
585 : const uint32_t& aAPZCId)
586 : {
587 0 : if (auto entry = mFrameMetricsTable.Lookup(aId)) {
588 : // The SharedFrameMetricsData may have been removed previously if
589 : // a SharedFrameMetricsData with the same ViewID but later APZCId had
590 : // been store and over wrote it.
591 0 : if (entry.Data()->GetAPZCId() == aAPZCId) {
592 0 : entry.Remove();
593 : }
594 : }
595 0 : return IPC_OK();
596 : }
597 :
598 0 : CompositorBridgeChild::SharedFrameMetricsData::SharedFrameMetricsData(
599 : const ipc::SharedMemoryBasic::Handle& metrics,
600 : const CrossProcessMutexHandle& handle,
601 : const uint64_t& aLayersId,
602 0 : const uint32_t& aAPZCId)
603 : : mMutex(nullptr)
604 0 : , mLayersId(aLayersId)
605 0 : , mAPZCId(aAPZCId)
606 : {
607 0 : mBuffer = new ipc::SharedMemoryBasic;
608 0 : mBuffer->SetHandle(metrics, ipc::SharedMemory::RightsReadOnly);
609 0 : mBuffer->Map(sizeof(FrameMetrics));
610 0 : mMutex = new CrossProcessMutex(handle);
611 0 : MOZ_COUNT_CTOR(SharedFrameMetricsData);
612 0 : }
613 :
614 0 : CompositorBridgeChild::SharedFrameMetricsData::~SharedFrameMetricsData()
615 : {
616 : // When the hash table deletes the class, delete
617 : // the shared memory and mutex.
618 0 : delete mMutex;
619 0 : mBuffer = nullptr;
620 0 : MOZ_COUNT_DTOR(SharedFrameMetricsData);
621 0 : }
622 :
623 : void
624 0 : CompositorBridgeChild::SharedFrameMetricsData::CopyFrameMetrics(FrameMetrics* aFrame)
625 : {
626 : const FrameMetrics* frame =
627 0 : static_cast<const FrameMetrics*>(mBuffer->memory());
628 0 : MOZ_ASSERT(frame);
629 0 : mMutex->Lock();
630 0 : *aFrame = *frame;
631 0 : mMutex->Unlock();
632 0 : }
633 :
634 : FrameMetrics::ViewID
635 0 : CompositorBridgeChild::SharedFrameMetricsData::GetViewID()
636 : {
637 : const FrameMetrics* frame =
638 0 : static_cast<const FrameMetrics*>(mBuffer->memory());
639 0 : MOZ_ASSERT(frame);
640 : // Not locking to read of mScrollId since it should not change after being
641 : // initially set.
642 0 : return frame->GetScrollId();
643 : }
644 :
645 : uint64_t
646 0 : CompositorBridgeChild::SharedFrameMetricsData::GetLayersId() const
647 : {
648 0 : return mLayersId;
649 : }
650 :
651 : uint32_t
652 0 : CompositorBridgeChild::SharedFrameMetricsData::GetAPZCId()
653 : {
654 0 : return mAPZCId;
655 : }
656 :
657 :
658 : mozilla::ipc::IPCResult
659 0 : CompositorBridgeChild::RecvRemotePaintIsReady()
660 : {
661 : // Used on the content thread, this bounces the message to the
662 : // TabParent (via the TabChild) if the notification was previously requested.
663 : // XPCOM gives a soup of compiler errors when trying to do_QueryReference
664 : // so I'm using static_cast<>
665 0 : MOZ_LAYERS_LOG(("[RemoteGfx] CompositorBridgeChild received RemotePaintIsReady"));
666 0 : RefPtr<nsISupports> iTabChildBase(do_QueryReferent(mWeakTabChild));
667 0 : if (!iTabChildBase) {
668 0 : MOZ_LAYERS_LOG(("[RemoteGfx] Note: TabChild was released before RemotePaintIsReady. "
669 : "MozAfterRemotePaint will not be sent to listener."));
670 0 : return IPC_OK();
671 : }
672 0 : TabChildBase* tabChildBase = static_cast<TabChildBase*>(iTabChildBase.get());
673 0 : TabChild* tabChild = static_cast<TabChild*>(tabChildBase);
674 0 : MOZ_ASSERT(tabChild);
675 0 : Unused << tabChild->SendRemotePaintIsReady();
676 0 : mWeakTabChild = nullptr;
677 0 : return IPC_OK();
678 : }
679 :
680 :
681 : void
682 0 : CompositorBridgeChild::RequestNotifyAfterRemotePaint(TabChild* aTabChild)
683 : {
684 0 : MOZ_ASSERT(aTabChild, "NULL TabChild not allowed in CompositorBridgeChild::RequestNotifyAfterRemotePaint");
685 0 : mWeakTabChild = do_GetWeakReference( static_cast<dom::TabChildBase*>(aTabChild) );
686 0 : if (!mCanSend) {
687 0 : return;
688 : }
689 0 : Unused << SendRequestNotifyAfterRemotePaint();
690 : }
691 :
692 : void
693 0 : CompositorBridgeChild::CancelNotifyAfterRemotePaint(TabChild* aTabChild)
694 : {
695 0 : RefPtr<nsISupports> iTabChildBase(do_QueryReferent(mWeakTabChild));
696 0 : if (!iTabChildBase) {
697 0 : return;
698 : }
699 0 : TabChildBase* tabChildBase = static_cast<TabChildBase*>(iTabChildBase.get());
700 0 : TabChild* tabChild = static_cast<TabChild*>(tabChildBase);
701 0 : if (tabChild == aTabChild) {
702 0 : mWeakTabChild = nullptr;
703 : }
704 : }
705 :
706 : bool
707 0 : CompositorBridgeChild::SendWillClose()
708 : {
709 0 : MOZ_RELEASE_ASSERT(mCanSend);
710 0 : return PCompositorBridgeChild::SendWillClose();
711 : }
712 :
713 : bool
714 0 : CompositorBridgeChild::SendPause()
715 : {
716 0 : if (!mCanSend) {
717 0 : return false;
718 : }
719 0 : return PCompositorBridgeChild::SendPause();
720 : }
721 :
722 : bool
723 0 : CompositorBridgeChild::SendResume()
724 : {
725 0 : if (!mCanSend) {
726 0 : return false;
727 : }
728 0 : return PCompositorBridgeChild::SendResume();
729 : }
730 :
731 : bool
732 0 : CompositorBridgeChild::SendNotifyChildCreated(const uint64_t& id,
733 : CompositorOptions* aOptions)
734 : {
735 0 : if (!mCanSend) {
736 0 : return false;
737 : }
738 0 : return PCompositorBridgeChild::SendNotifyChildCreated(id, aOptions);
739 : }
740 :
741 : bool
742 1 : CompositorBridgeChild::SendAdoptChild(const uint64_t& id)
743 : {
744 1 : if (!mCanSend) {
745 0 : return false;
746 : }
747 1 : return PCompositorBridgeChild::SendAdoptChild(id);
748 : }
749 :
750 : bool
751 0 : CompositorBridgeChild::SendMakeSnapshot(const SurfaceDescriptor& inSnapshot, const gfx::IntRect& dirtyRect)
752 : {
753 0 : if (!mCanSend) {
754 0 : return false;
755 : }
756 0 : return PCompositorBridgeChild::SendMakeSnapshot(inSnapshot, dirtyRect);
757 : }
758 :
759 : bool
760 1 : CompositorBridgeChild::SendFlushRendering()
761 : {
762 1 : if (!mCanSend) {
763 0 : return false;
764 : }
765 1 : return PCompositorBridgeChild::SendFlushRendering();
766 : }
767 :
768 : bool
769 0 : CompositorBridgeChild::SendStartFrameTimeRecording(const int32_t& bufferSize, uint32_t* startIndex)
770 : {
771 0 : if (!mCanSend) {
772 0 : return false;
773 : }
774 0 : return PCompositorBridgeChild::SendStartFrameTimeRecording(bufferSize, startIndex);
775 : }
776 :
777 : bool
778 0 : CompositorBridgeChild::SendStopFrameTimeRecording(const uint32_t& startIndex, nsTArray<float>* intervals)
779 : {
780 0 : if (!mCanSend) {
781 0 : return false;
782 : }
783 0 : return PCompositorBridgeChild::SendStopFrameTimeRecording(startIndex, intervals);
784 : }
785 :
786 : bool
787 1 : CompositorBridgeChild::SendNotifyRegionInvalidated(const nsIntRegion& region)
788 : {
789 1 : if (!mCanSend) {
790 0 : return false;
791 : }
792 1 : return PCompositorBridgeChild::SendNotifyRegionInvalidated(region);
793 : }
794 :
795 : bool
796 0 : CompositorBridgeChild::SendRequestNotifyAfterRemotePaint()
797 : {
798 0 : if (!mCanSend) {
799 0 : return false;
800 : }
801 0 : return PCompositorBridgeChild::SendRequestNotifyAfterRemotePaint();
802 : }
803 :
804 : bool
805 0 : CompositorBridgeChild::SendClearApproximatelyVisibleRegions(uint64_t aLayersId,
806 : uint32_t aPresShellId)
807 : {
808 0 : if (!mCanSend) {
809 0 : return false;
810 : }
811 0 : return PCompositorBridgeChild::SendClearApproximatelyVisibleRegions(aLayersId,
812 0 : aPresShellId);
813 : }
814 :
815 : bool
816 0 : CompositorBridgeChild::SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
817 : const CSSIntRegion& aRegion)
818 : {
819 0 : if (!mCanSend) {
820 0 : return false;
821 : }
822 0 : return PCompositorBridgeChild::SendNotifyApproximatelyVisibleRegion(aGuid, aRegion);
823 : }
824 :
825 : bool
826 0 : CompositorBridgeChild::SendAllPluginsCaptured()
827 : {
828 0 : if (!mCanSend) {
829 0 : return false;
830 : }
831 0 : return PCompositorBridgeChild::SendAllPluginsCaptured();
832 : }
833 :
834 : PTextureChild*
835 9 : CompositorBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
836 : const LayersBackend&,
837 : const TextureFlags&,
838 : const uint64_t&,
839 : const uint64_t& aSerial,
840 : const wr::MaybeExternalImageId& aExternalImageId)
841 : {
842 9 : return TextureClient::CreateIPDLActor();
843 : }
844 :
845 : bool
846 6 : CompositorBridgeChild::DeallocPTextureChild(PTextureChild* actor)
847 : {
848 6 : return TextureClient::DestroyIPDLActor(actor);
849 : }
850 :
851 : mozilla::ipc::IPCResult
852 0 : CompositorBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
853 : {
854 0 : for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
855 0 : const AsyncParentMessageData& message = aMessages[i];
856 :
857 0 : switch (message.type()) {
858 : case AsyncParentMessageData::TOpNotifyNotUsed: {
859 0 : const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
860 0 : NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
861 0 : break;
862 : }
863 : default:
864 0 : NS_ERROR("unknown AsyncParentMessageData type");
865 0 : return IPC_FAIL_NO_REASON(this);
866 : }
867 : }
868 0 : return IPC_OK();
869 : }
870 :
871 : mozilla::ipc::IPCResult
872 1 : CompositorBridgeChild::RecvObserveLayerUpdate(const uint64_t& aLayersId,
873 : const uint64_t& aEpoch,
874 : const bool& aActive)
875 : {
876 : // This message is sent via the window compositor, not the tab compositor -
877 : // however it still has a layers id.
878 1 : MOZ_ASSERT(aLayersId);
879 1 : MOZ_ASSERT(XRE_IsParentProcess());
880 :
881 2 : if (RefPtr<dom::TabParent> tab = dom::TabParent::GetTabParentFromLayersId(aLayersId)) {
882 1 : tab->LayerTreeUpdate(aEpoch, aActive);
883 : }
884 1 : return IPC_OK();
885 : }
886 :
887 : void
888 33 : CompositorBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient)
889 : {
890 33 : if (!aClient) {
891 0 : return;
892 : }
893 :
894 33 : if (!(aClient->GetFlags() & TextureFlags::RECYCLE)) {
895 33 : return;
896 : }
897 :
898 0 : aClient->SetLastFwdTransactionId(GetFwdTransactionId());
899 0 : mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient);
900 : }
901 :
902 : void
903 0 : CompositorBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
904 : {
905 0 : if (auto entry = mTexturesWaitingRecycled.Lookup(aTextureId)) {
906 0 : if (aFwdTransactionId < entry.Data()->GetLastFwdTransactionId()) {
907 : // Released on host side, but client already requested newer use texture.
908 0 : return;
909 : }
910 0 : entry.Remove();
911 : }
912 : }
913 :
914 : void
915 0 : CompositorBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
916 : {
917 0 : mTexturesWaitingRecycled.Remove(aTextureId);
918 0 : }
919 :
920 : TextureClientPool*
921 0 : CompositorBridgeChild::GetTexturePool(KnowsCompositor* aAllocator,
922 : SurfaceFormat aFormat,
923 : TextureFlags aFlags)
924 : {
925 0 : for (size_t i = 0; i < mTexturePools.Length(); i++) {
926 0 : if (mTexturePools[i]->GetBackend() == aAllocator->GetCompositorBackendType() &&
927 0 : mTexturePools[i]->GetMaxTextureSize() == aAllocator->GetMaxTextureSize() &&
928 0 : mTexturePools[i]->GetFormat() == aFormat &&
929 0 : mTexturePools[i]->GetFlags() == aFlags) {
930 0 : return mTexturePools[i];
931 : }
932 : }
933 :
934 0 : mTexturePools.AppendElement(
935 0 : new TextureClientPool(aAllocator->GetCompositorBackendType(),
936 0 : aAllocator->GetMaxTextureSize(),
937 : aFormat,
938 0 : gfx::gfxVars::TileSize(),
939 : aFlags,
940 0 : gfxPrefs::LayersTilePoolShrinkTimeout(),
941 0 : gfxPrefs::LayersTilePoolClearTimeout(),
942 0 : gfxPrefs::LayersTileInitialPoolSize(),
943 0 : gfxPrefs::LayersTilePoolUnusedSize(),
944 0 : this));
945 :
946 0 : return mTexturePools.LastElement();
947 : }
948 :
949 : void
950 0 : CompositorBridgeChild::HandleMemoryPressure()
951 : {
952 0 : for (size_t i = 0; i < mTexturePools.Length(); i++) {
953 0 : mTexturePools[i]->Clear();
954 : }
955 0 : }
956 :
957 : void
958 0 : CompositorBridgeChild::ClearTexturePool()
959 : {
960 0 : for (size_t i = 0; i < mTexturePools.Length(); i++) {
961 0 : mTexturePools[i]->Clear();
962 : }
963 0 : }
964 :
965 : FixedSizeSmallShmemSectionAllocator*
966 0 : CompositorBridgeChild::GetTileLockAllocator()
967 : {
968 0 : if (!IPCOpen()) {
969 0 : return nullptr;
970 : }
971 :
972 0 : if (!mSectionAllocator) {
973 0 : mSectionAllocator = new FixedSizeSmallShmemSectionAllocator(this);
974 : }
975 0 : return mSectionAllocator;
976 : }
977 :
978 : PTextureChild*
979 9 : CompositorBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
980 : LayersBackend aLayersBackend,
981 : TextureFlags aFlags,
982 : uint64_t aSerial,
983 : wr::MaybeExternalImageId& aExternalImageId,
984 : nsIEventTarget* aTarget)
985 : {
986 18 : PTextureChild* textureChild = AllocPTextureChild(
987 9 : aSharedData, aLayersBackend, aFlags, 0 /* FIXME */, aSerial, aExternalImageId);
988 :
989 : // Do the DOM labeling.
990 9 : if (aTarget) {
991 1 : SetEventTargetForActor(textureChild, aTarget);
992 : }
993 :
994 18 : return SendPTextureConstructor(
995 18 : textureChild, aSharedData, aLayersBackend, aFlags, 0 /* FIXME? */, aSerial, aExternalImageId);
996 : }
997 :
998 : bool
999 1 : CompositorBridgeChild::AllocUnsafeShmem(size_t aSize,
1000 : ipc::SharedMemory::SharedMemoryType aType,
1001 : ipc::Shmem* aShmem)
1002 : {
1003 1 : ShmemAllocated(this);
1004 1 : return PCompositorBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
1005 : }
1006 :
1007 : bool
1008 0 : CompositorBridgeChild::AllocShmem(size_t aSize,
1009 : ipc::SharedMemory::SharedMemoryType aType,
1010 : ipc::Shmem* aShmem)
1011 : {
1012 0 : ShmemAllocated(this);
1013 0 : return PCompositorBridgeChild::AllocShmem(aSize, aType, aShmem);
1014 : }
1015 :
1016 : bool
1017 0 : CompositorBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
1018 : {
1019 0 : if (!mCanSend) {
1020 0 : return false;
1021 : }
1022 0 : return PCompositorBridgeChild::DeallocShmem(aShmem);
1023 : }
1024 :
1025 : widget::PCompositorWidgetChild*
1026 0 : CompositorBridgeChild::AllocPCompositorWidgetChild(const CompositorWidgetInitData& aInitData)
1027 : {
1028 : // We send the constructor manually.
1029 0 : MOZ_CRASH("Should not be called");
1030 : return nullptr;
1031 : }
1032 :
1033 : bool
1034 0 : CompositorBridgeChild::DeallocPCompositorWidgetChild(PCompositorWidgetChild* aActor)
1035 : {
1036 : #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
1037 0 : delete aActor;
1038 0 : return true;
1039 : #else
1040 : return false;
1041 : #endif
1042 : }
1043 :
1044 : PAPZCTreeManagerChild*
1045 1 : CompositorBridgeChild::AllocPAPZCTreeManagerChild(const uint64_t& aLayersId)
1046 : {
1047 1 : APZCTreeManagerChild* child = new APZCTreeManagerChild();
1048 1 : child->AddRef();
1049 1 : if (aLayersId != 0) {
1050 1 : TabChild* tabChild = TabChild::GetFrom(aLayersId);
1051 1 : if (tabChild) {
1052 1 : SetEventTargetForActor(
1053 2 : child, tabChild->TabGroup()->EventTargetFor(TaskCategory::Other));
1054 1 : MOZ_ASSERT(child->GetActorEventTarget());
1055 : }
1056 : }
1057 :
1058 1 : return child;
1059 : }
1060 :
1061 : PAPZChild*
1062 0 : CompositorBridgeChild::AllocPAPZChild(const uint64_t& aLayersId)
1063 : {
1064 : // We send the constructor manually.
1065 0 : MOZ_CRASH("Should not be called");
1066 : return nullptr;
1067 : }
1068 :
1069 : bool
1070 0 : CompositorBridgeChild::DeallocPAPZChild(PAPZChild* aActor)
1071 : {
1072 0 : delete aActor;
1073 0 : return true;
1074 : }
1075 :
1076 : bool
1077 0 : CompositorBridgeChild::DeallocPAPZCTreeManagerChild(PAPZCTreeManagerChild* aActor)
1078 : {
1079 0 : APZCTreeManagerChild* parent = static_cast<APZCTreeManagerChild*>(aActor);
1080 0 : parent->Release();
1081 0 : return true;
1082 : }
1083 :
1084 : void
1085 29 : CompositorBridgeChild::WillEndTransaction()
1086 : {
1087 29 : ResetShmemCounter();
1088 29 : }
1089 :
1090 : PWebRenderBridgeChild*
1091 0 : CompositorBridgeChild::AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId,
1092 : const LayoutDeviceIntSize&,
1093 : TextureFactoryIdentifier*,
1094 : uint32_t *aIdNamespace)
1095 : {
1096 0 : WebRenderBridgeChild* child = new WebRenderBridgeChild(aPipelineId);
1097 0 : child->AddIPDLReference();
1098 0 : return child;
1099 : }
1100 :
1101 : bool
1102 0 : CompositorBridgeChild::DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor)
1103 : {
1104 0 : WebRenderBridgeChild* child = static_cast<WebRenderBridgeChild*>(aActor);
1105 0 : child->ReleaseIPDLReference();
1106 0 : return true;
1107 : }
1108 :
1109 : uint64_t
1110 9 : CompositorBridgeChild::GetNextResourceId()
1111 : {
1112 9 : ++mResourceId;
1113 9 : MOZ_RELEASE_ASSERT(mResourceId != UINT32_MAX);
1114 :
1115 9 : uint64_t id = mIdNamespace;
1116 9 : id = (id << 32) | mResourceId;
1117 :
1118 9 : return id;
1119 : }
1120 :
1121 : wr::MaybeExternalImageId
1122 9 : CompositorBridgeChild::GetNextExternalImageId()
1123 : {
1124 9 : return Some(wr::ToExternalImageId(GetNextResourceId()));
1125 : }
1126 :
1127 : wr::PipelineId
1128 0 : CompositorBridgeChild::GetNextPipelineId()
1129 : {
1130 0 : return wr::AsPipelineId(GetNextResourceId());
1131 : }
1132 :
1133 : void
1134 0 : CompositorBridgeChild::NotifyBeginAsyncPaint()
1135 : {
1136 0 : MOZ_ASSERT(NS_IsMainThread());
1137 :
1138 0 : MonitorAutoLock lock(mPaintLock);
1139 :
1140 : // We must not be waiting for paints to complete yet. This would imply we
1141 : // started a new paint without waiting for a previous one, which could lead to
1142 : // incorrect rendering or IPDL deadlocks.
1143 0 : MOZ_ASSERT(!mIsWaitingForPaint);
1144 :
1145 0 : mOutstandingAsyncPaints++;
1146 0 : }
1147 :
1148 : void
1149 0 : CompositorBridgeChild::NotifyFinishedAsyncPaint()
1150 : {
1151 0 : MOZ_ASSERT(PaintThread::IsOnPaintThread());
1152 :
1153 0 : MonitorAutoLock lock(mPaintLock);
1154 :
1155 0 : mOutstandingAsyncPaints--;
1156 :
1157 : // It's possible that we painted so fast that the main thread never reached
1158 : // the code that starts delaying messages. If so, mIsWaitingForPaint will be
1159 : // false, and we can safely return.
1160 0 : if (mIsWaitingForPaint && mOutstandingAsyncPaints == 0) {
1161 0 : ResumeIPCAfterAsyncPaint();
1162 :
1163 : // Notify the main thread in case it's blocking. We do this unconditionally
1164 : // to avoid deadlocking.
1165 0 : lock.Notify();
1166 : }
1167 0 : }
1168 :
1169 : void
1170 28 : CompositorBridgeChild::PostponeMessagesIfAsyncPainting()
1171 : {
1172 28 : MOZ_ASSERT(NS_IsMainThread());
1173 :
1174 56 : MonitorAutoLock lock(mPaintLock);
1175 :
1176 28 : MOZ_ASSERT(!mIsWaitingForPaint);
1177 :
1178 28 : if (mOutstandingAsyncPaints > 0) {
1179 0 : mIsWaitingForPaint = true;
1180 0 : GetIPCChannel()->BeginPostponingSends();
1181 : }
1182 28 : }
1183 :
1184 : void
1185 0 : CompositorBridgeChild::ResumeIPCAfterAsyncPaint()
1186 : {
1187 : // Note: the caller is responsible for holding the lock.
1188 0 : mPaintLock.AssertCurrentThreadOwns();
1189 0 : MOZ_ASSERT(PaintThread::IsOnPaintThread());
1190 0 : MOZ_ASSERT(mOutstandingAsyncPaints == 0);
1191 0 : MOZ_ASSERT(mIsWaitingForPaint);
1192 :
1193 0 : mIsWaitingForPaint = false;
1194 :
1195 : // It's also possible that the channel has shut down already.
1196 0 : if (!mCanSend || mActorDestroyed) {
1197 0 : return;
1198 : }
1199 :
1200 0 : GetIPCChannel()->StopPostponingSends();
1201 : }
1202 :
1203 : void
1204 29 : CompositorBridgeChild::FlushAsyncPaints()
1205 : {
1206 29 : MOZ_ASSERT(NS_IsMainThread());
1207 :
1208 58 : MonitorAutoLock lock(mPaintLock);
1209 29 : while (mIsWaitingForPaint) {
1210 0 : lock.Wait();
1211 : }
1212 29 : }
1213 :
1214 : } // namespace layers
1215 : } // namespace mozilla
|