Coverage Report

Created: 2018-09-25 14:53

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