Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/ipc/ImageBridgeChild.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 "ImageBridgeChild.h"
8
#include <vector>                       // for vector
9
#include "ImageBridgeParent.h"          // for ImageBridgeParent
10
#include "ImageContainer.h"             // for ImageContainer
11
#include "Layers.h"                     // for Layer, etc
12
#include "ShadowLayers.h"               // for ShadowLayerForwarder
13
#include "base/message_loop.h"          // for MessageLoop
14
#include "base/platform_thread.h"       // for PlatformThread
15
#include "base/process.h"               // for ProcessId
16
#include "base/task.h"                  // for NewRunnableFunction, etc
17
#include "base/thread.h"                // for Thread
18
#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
19
#include "mozilla/Monitor.h"            // for Monitor, MonitorAutoLock
20
#include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
21
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
22
#include "mozilla/ipc/Transport.h"      // for Transport
23
#include "mozilla/gfx/Point.h"          // for IntSize
24
#include "mozilla/layers/AsyncCanvasRenderer.h"
25
#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
26
#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
27
#include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
28
#include "mozilla/layers/CompositorThread.h"
29
#include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
30
#include "mozilla/layers/ImageClient.h"  // for ImageClient
31
#include "mozilla/layers/LayersMessages.h"  // for CompositableOperation
32
#include "mozilla/layers/TextureClient.h"  // for TextureClient
33
#include "mozilla/dom/ContentChild.h"
34
#include "mozilla/mozalloc.h"           // for operator new, etc
35
#include "mtransport/runnable_utils.h"
36
#include "nsContentUtils.h"
37
#include "nsISupportsImpl.h"            // for ImageContainer::AddRef, etc
38
#include "nsTArray.h"                   // for AutoTArray, nsTArray, etc
39
#include "nsTArrayForwardDeclare.h"     // for AutoTArray
40
#include "nsThreadUtils.h"              // for NS_IsMainThread
41
#include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
42
#include "mozilla/StaticMutex.h"
43
#include "mozilla/StaticPtr.h"          // for StaticRefPtr
44
#include "mozilla/layers/TextureClient.h"
45
#include "SynchronousTask.h"
46
47
#if defined(XP_WIN)
48
#include "mozilla/gfx/DeviceManagerDx.h"
49
#endif
50
51
namespace mozilla {
52
namespace ipc {
53
class Shmem;
54
} // namespace ipc
55
56
namespace layers {
57
58
using base::Thread;
59
using base::ProcessId;
60
using namespace mozilla::ipc;
61
using namespace mozilla::gfx;
62
using namespace mozilla::media;
63
64
typedef std::vector<CompositableOperation> OpVector;
65
typedef nsTArray<OpDestroy> OpDestroyVector;
66
67
struct CompositableTransaction
68
{
69
  CompositableTransaction()
70
  : mFinished(true)
71
0
  {}
72
  ~CompositableTransaction()
73
0
  {
74
0
    End();
75
0
  }
76
  bool Finished() const
77
0
  {
78
0
    return mFinished;
79
0
  }
80
  void Begin()
81
0
  {
82
0
    MOZ_ASSERT(mFinished);
83
0
    mFinished = false;
84
0
  }
85
  void End()
86
0
  {
87
0
    mFinished = true;
88
0
    mOperations.clear();
89
0
    mDestroyedActors.Clear();
90
0
  }
91
  bool IsEmpty() const
92
0
  {
93
0
    return mOperations.empty() && mDestroyedActors.IsEmpty();
94
0
  }
95
  void AddNoSwapEdit(const CompositableOperation& op)
96
0
  {
97
0
    MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
98
0
    mOperations.push_back(op);
99
0
  }
100
101
  OpVector mOperations;
102
  OpDestroyVector mDestroyedActors;
103
104
  bool mFinished;
105
};
106
107
struct AutoEndTransaction {
108
0
  explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
109
0
  ~AutoEndTransaction() { mTxn->End(); }
110
  CompositableTransaction* mTxn;
111
};
112
113
void
114
ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
115
                              const nsTArray<TimedTextureClient>& aTextures)
116
0
{
117
0
  MOZ_ASSERT(aCompositable);
118
0
  MOZ_ASSERT(aCompositable->GetIPCHandle());
119
0
  MOZ_ASSERT(aCompositable->IsConnected());
120
0
121
0
  AutoTArray<TimedTexture,4> textures;
122
0
123
0
  for (auto& t : aTextures) {
124
0
    MOZ_ASSERT(t.mTextureClient);
125
0
    MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
126
0
127
0
    if (!t.mTextureClient->IsSharedWithCompositor()) {
128
0
      return;
129
0
    }
130
0
131
0
    bool readLocked = t.mTextureClient->OnForwardedToHost();
132
0
    textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
133
0
                                        t.mTimeStamp, t.mPictureRect,
134
0
                                        t.mFrameID, t.mProducerID,
135
0
                                        readLocked));
136
0
137
0
    // Wait end of usage on host side if TextureFlags::RECYCLE is set
138
0
    HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
139
0
  }
140
0
  mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(),
141
0
                                            OpUseTexture(textures)));
142
0
}
143
144
void
145
ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
146
                                            TextureClient* aTextureOnBlack,
147
                                            TextureClient* aTextureOnWhite)
148
0
{
149
0
  MOZ_CRASH("should not be called");
150
0
}
151
152
void
153
ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient)
154
0
{
155
0
  // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE is set on ImageBridge.
156
0
  if (!aClient ||
157
0
      !(aClient->GetFlags() & TextureFlags::RECYCLE)) {
158
0
    return;
159
0
  }
160
0
  aClient->SetLastFwdTransactionId(GetFwdTransactionId());
161
0
  mTexturesWaitingRecycled.emplace(aClient->GetSerial(), aClient);
162
0
}
163
164
void
165
ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
166
0
{
167
0
  auto it = mTexturesWaitingRecycled.find(aTextureId);
168
0
  if (it != mTexturesWaitingRecycled.end()) {
169
0
    if (aFwdTransactionId < it->second->GetLastFwdTransactionId()) {
170
0
      // Released on host side, but client already requested newer use texture.
171
0
      return;
172
0
    }
173
0
    mTexturesWaitingRecycled.erase(it);
174
0
  }
175
0
}
176
177
void
178
ImageBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
179
0
{
180
0
  MOZ_ASSERT(InImageBridgeChildThread());
181
0
  mTexturesWaitingRecycled.erase(aTextureId);
182
0
}
183
184
// Singleton
185
static StaticMutex sImageBridgeSingletonLock;
186
static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
187
static Thread *sImageBridgeChildThread = nullptr;
188
189
// dispatched function
190
void
191
ImageBridgeChild::ShutdownStep1(SynchronousTask* aTask)
192
0
{
193
0
  AutoCompleteTask complete(aTask);
194
0
195
0
  MOZ_ASSERT(InImageBridgeChildThread(),
196
0
             "Should be in ImageBridgeChild thread.");
197
0
198
0
  MediaSystemResourceManager::Shutdown();
199
0
200
0
  // Force all managed protocols to shut themselves down cleanly
201
0
  InfallibleTArray<PTextureChild*> textures;
202
0
  ManagedPTextureChild(textures);
203
0
  for (int i = textures.Length() - 1; i >= 0; --i) {
204
0
    RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
205
0
    if (client) {
206
0
      client->Destroy();
207
0
    }
208
0
  }
209
0
210
0
  if (mCanSend) {
211
0
    SendWillClose();
212
0
  }
213
0
  MarkShutDown();
214
0
215
0
  // From now on, no message can be sent through the image bridge from the
216
0
  // client side except the final Stop message.
217
0
}
218
219
// dispatched function
220
void
221
ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask)
222
0
{
223
0
  AutoCompleteTask complete(aTask);
224
0
225
0
  MOZ_ASSERT(InImageBridgeChildThread(),
226
0
             "Should be in ImageBridgeChild thread.");
227
0
  if (!mDestroyed) {
228
0
    Close();
229
0
  }
230
0
}
231
232
void
233
ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
234
0
{
235
0
  mCanSend = false;
236
0
  mDestroyed = true;
237
0
  {
238
0
    MutexAutoLock lock(mContainerMapLock);
239
0
    mImageContainerListeners.clear();
240
0
  }
241
0
}
242
243
void
244
ImageBridgeChild::DeallocPImageBridgeChild()
245
0
{
246
0
  this->Release();
247
0
}
248
249
void
250
ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask,
251
                                        RefPtr<ImageClient>* result,
252
                                        CompositableType aType,
253
                                        ImageContainer* aImageContainer)
254
0
{
255
0
  AutoCompleteTask complete(aTask);
256
0
  *result = CreateImageClientNow(aType, aImageContainer);
257
0
}
258
259
// dispatched function
260
void
261
ImageBridgeChild::CreateCanvasClientSync(SynchronousTask* aTask,
262
                                         CanvasClient::CanvasClientType aType,
263
                                         TextureFlags aFlags,
264
                                         RefPtr<CanvasClient>* const outResult)
265
0
{
266
0
  AutoCompleteTask complete(aTask);
267
0
  *outResult = CreateCanvasClientNow(aType, aFlags);
268
0
}
269
270
ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace)
271
  : mNamespace(aNamespace)
272
  , mCanSend(false)
273
  , mDestroyed(false)
274
  , mFwdTransactionId(0)
275
  , mContainerMapLock("ImageBridgeChild.mContainerMapLock")
276
0
{
277
0
  MOZ_ASSERT(mNamespace);
278
0
  MOZ_ASSERT(NS_IsMainThread());
279
0
280
0
  mTxn = new CompositableTransaction();
281
0
}
282
283
ImageBridgeChild::~ImageBridgeChild()
284
0
{
285
0
  delete mTxn;
286
0
}
287
288
void
289
ImageBridgeChild::MarkShutDown()
290
0
{
291
0
  mTexturesWaitingRecycled.clear();
292
0
293
0
  mCanSend = false;
294
0
}
295
296
void
297
ImageBridgeChild::Connect(CompositableClient* aCompositable,
298
                          ImageContainer* aImageContainer)
299
0
{
300
0
  MOZ_ASSERT(aCompositable);
301
0
  MOZ_ASSERT(InImageBridgeChildThread());
302
0
  MOZ_ASSERT(CanSend());
303
0
304
0
  // Note: this is static, rather than per-IBC, so IDs are not re-used across
305
0
  // ImageBridgeChild instances. This is relevant for the GPU process, where
306
0
  // we don't want old IDs to potentially leak into a recreated ImageBridge.
307
0
  static uint64_t sNextID = 1;
308
0
  uint64_t id = sNextID++;
309
0
310
0
  // ImageClient of ImageContainer provides aImageContainer.
311
0
  // But offscreen canvas does not provide it.
312
0
  if (aImageContainer) {
313
0
    MutexAutoLock lock(mContainerMapLock);
314
0
    MOZ_ASSERT(mImageContainerListeners.find(id) == mImageContainerListeners.end());
315
0
    mImageContainerListeners.emplace(id, aImageContainer->GetImageContainerListener());
316
0
  }
317
0
318
0
  CompositableHandle handle(id);
319
0
  aCompositable->InitIPDL(handle);
320
0
  SendNewCompositable(handle, aCompositable->GetTextureInfo(), GetCompositorBackendType());
321
0
}
322
323
void
324
ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle)
325
0
{
326
0
  MutexAutoLock lock(mContainerMapLock);
327
0
  mImageContainerListeners.erase(aHandle.Value());
328
0
}
329
330
Thread* ImageBridgeChild::GetThread() const
331
0
{
332
0
  return sImageBridgeChildThread;
333
0
}
334
335
/* static */ RefPtr<ImageBridgeChild>
336
ImageBridgeChild::GetSingleton()
337
0
{
338
0
  StaticMutexAutoLock lock(sImageBridgeSingletonLock);
339
0
  return sImageBridgeChildSingleton;
340
0
}
341
342
void
343
ImageBridgeChild::UpdateImageClient(RefPtr<ImageContainer> aContainer)
344
0
{
345
0
  if (!aContainer) {
346
0
    return;
347
0
  }
348
0
349
0
  if (!InImageBridgeChildThread()) {
350
0
    RefPtr<Runnable> runnable = WrapRunnable(
351
0
      RefPtr<ImageBridgeChild>(this),
352
0
      &ImageBridgeChild::UpdateImageClient,
353
0
      aContainer);
354
0
    GetMessageLoop()->PostTask(runnable.forget());
355
0
    return;
356
0
  }
357
0
358
0
  if (!CanSend()) {
359
0
    return;
360
0
  }
361
0
362
0
  RefPtr<ImageClient> client = aContainer->GetImageClient();
363
0
  if (NS_WARN_IF(!client)) {
364
0
    return;
365
0
  }
366
0
367
0
  // If the client has become disconnected before this event was dispatched,
368
0
  // early return now.
369
0
  if (!client->IsConnected()) {
370
0
    return;
371
0
  }
372
0
373
0
  BeginTransaction();
374
0
  client->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
375
0
  EndTransaction();
376
0
}
377
378
void
379
ImageBridgeChild::UpdateAsyncCanvasRendererSync(SynchronousTask* aTask, AsyncCanvasRenderer* aWrapper)
380
0
{
381
0
  AutoCompleteTask complete(aTask);
382
0
383
0
  UpdateAsyncCanvasRendererNow(aWrapper);
384
0
}
385
386
void
387
ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper)
388
0
{
389
0
  aWrapper->GetCanvasClient()->UpdateAsync(aWrapper);
390
0
391
0
  if (InImageBridgeChildThread()) {
392
0
    UpdateAsyncCanvasRendererNow(aWrapper);
393
0
    return;
394
0
  }
395
0
396
0
  SynchronousTask task("UpdateAsyncCanvasRenderer Lock");
397
0
398
0
  RefPtr<Runnable> runnable = WrapRunnable(
399
0
    RefPtr<ImageBridgeChild>(this),
400
0
    &ImageBridgeChild::UpdateAsyncCanvasRendererSync,
401
0
    &task,
402
0
    aWrapper);
403
0
  GetMessageLoop()->PostTask(runnable.forget());
404
0
405
0
  task.Wait();
406
0
}
407
408
void
409
ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper)
410
0
{
411
0
  MOZ_ASSERT(aWrapper);
412
0
413
0
  if (!CanSend()) {
414
0
    return;
415
0
  }
416
0
417
0
  BeginTransaction();
418
0
  aWrapper->GetCanvasClient()->Updated();
419
0
  EndTransaction();
420
0
}
421
422
void
423
ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
424
                                     ImageClient* aClient,
425
                                     ImageContainer* aContainer)
426
0
{
427
0
  AutoCompleteTask complete(aTask);
428
0
429
0
  if (!CanSend()) {
430
0
    return;
431
0
  }
432
0
433
0
  MOZ_ASSERT(aClient);
434
0
  BeginTransaction();
435
0
  if (aContainer) {
436
0
    aContainer->ClearImagesFromImageBridge();
437
0
  }
438
0
  aClient->FlushAllImages();
439
0
  EndTransaction();
440
0
}
441
442
void
443
ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer)
444
0
{
445
0
  MOZ_ASSERT(aClient);
446
0
  MOZ_ASSERT(!InImageBridgeChildThread());
447
0
448
0
  if (InImageBridgeChildThread()) {
449
0
    NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
450
0
    return;
451
0
  }
452
0
453
0
  SynchronousTask task("FlushAllImages Lock");
454
0
455
0
  // RefPtrs on arguments are not needed since this dispatches synchronously.
456
0
  RefPtr<Runnable> runnable = WrapRunnable(
457
0
    RefPtr<ImageBridgeChild>(this),
458
0
    &ImageBridgeChild::FlushAllImagesSync,
459
0
    &task,
460
0
    aClient,
461
0
    aContainer);
462
0
  GetMessageLoop()->PostTask(runnable.forget());
463
0
464
0
  task.Wait();
465
0
}
466
467
void
468
ImageBridgeChild::BeginTransaction()
469
0
{
470
0
  MOZ_ASSERT(CanSend());
471
0
  MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
472
0
  UpdateFwdTransactionId();
473
0
  mTxn->Begin();
474
0
}
475
476
void
477
ImageBridgeChild::EndTransaction()
478
0
{
479
0
  MOZ_ASSERT(CanSend());
480
0
  MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
481
0
482
0
  AutoEndTransaction _(mTxn);
483
0
484
0
  if (mTxn->IsEmpty()) {
485
0
    return;
486
0
  }
487
0
488
0
  AutoTArray<CompositableOperation, 10> cset;
489
0
  cset.SetCapacity(mTxn->mOperations.size());
490
0
  if (!mTxn->mOperations.empty()) {
491
0
    cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
492
0
  }
493
0
494
0
  if (!IsSameProcess()) {
495
0
    ShadowLayerForwarder::PlatformSyncBeforeUpdate();
496
0
  }
497
0
498
0
  if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
499
0
    NS_WARNING("could not send async texture transaction");
500
0
    return;
501
0
  }
502
0
}
503
504
bool
505
ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
506
0
{
507
0
  MOZ_ASSERT(NS_IsMainThread());
508
0
509
0
  gfxPlatform::GetPlatform();
510
0
511
0
  if (!sImageBridgeChildThread) {
512
0
    sImageBridgeChildThread = new Thread("ImageBridgeChild");
513
0
    bool success = sImageBridgeChildThread->Start();
514
0
    MOZ_RELEASE_ASSERT(success, "Failed to start ImageBridgeChild thread!");
515
0
  }
516
0
517
0
  RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
518
0
519
0
  RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
520
0
    "layers::ImageBridgeChild::Bind",
521
0
    child,
522
0
    &ImageBridgeChild::Bind,
523
0
    std::move(aEndpoint));
524
0
  child->GetMessageLoop()->PostTask(runnable.forget());
525
0
526
0
  // Assign this after so other threads can't post messages before we connect to IPDL.
527
0
  {
528
0
    StaticMutexAutoLock lock(sImageBridgeSingletonLock);
529
0
    sImageBridgeChildSingleton = child;
530
0
  }
531
0
532
0
  return true;
533
0
}
534
535
bool
536
ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
537
0
{
538
0
  MOZ_ASSERT(NS_IsMainThread());
539
0
540
0
  // Note that at this point, ActorDestroy may not have been called yet,
541
0
  // meaning mCanSend is still true. In this case we will try to send a
542
0
  // synchronous WillClose message to the parent, and will certainly get a
543
0
  // false result and a MsgDropped processing error. This is okay.
544
0
  ShutdownSingleton();
545
0
546
0
  return InitForContent(std::move(aEndpoint), aNamespace);
547
0
}
548
549
void
550
ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint)
551
0
{
552
0
  if (!aEndpoint.Bind(this)) {
553
0
    return;
554
0
  }
555
0
556
0
  // This reference is dropped in DeallocPImageBridgeChild.
557
0
  this->AddRef();
558
0
559
0
  mCanSend = true;
560
0
}
561
562
void
563
ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent)
564
0
{
565
0
  MessageLoop *parentMsgLoop = aParent->GetMessageLoop();
566
0
  ipc::MessageChannel *parentChannel = aParent->GetIPCChannel();
567
0
  Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
568
0
569
0
  // This reference is dropped in DeallocPImageBridgeChild.
570
0
  this->AddRef();
571
0
572
0
  mCanSend = true;
573
0
}
574
575
/* static */ void
576
ImageBridgeChild::ShutDown()
577
0
{
578
0
  MOZ_ASSERT(NS_IsMainThread());
579
0
580
0
  ShutdownSingleton();
581
0
582
0
  delete sImageBridgeChildThread;
583
0
  sImageBridgeChildThread = nullptr;
584
0
}
585
586
/* static */ void
587
ImageBridgeChild::ShutdownSingleton()
588
0
{
589
0
  MOZ_ASSERT(NS_IsMainThread());
590
0
591
0
  if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
592
0
    child->WillShutdown();
593
0
594
0
    StaticMutexAutoLock lock(sImageBridgeSingletonLock);
595
0
    sImageBridgeChildSingleton = nullptr;
596
0
  }
597
0
}
598
599
void
600
ImageBridgeChild::WillShutdown()
601
0
{
602
0
  {
603
0
    SynchronousTask task("ImageBridge ShutdownStep1 lock");
604
0
605
0
    RefPtr<Runnable> runnable = WrapRunnable(
606
0
      RefPtr<ImageBridgeChild>(this),
607
0
      &ImageBridgeChild::ShutdownStep1,
608
0
      &task);
609
0
    GetMessageLoop()->PostTask(runnable.forget());
610
0
611
0
    task.Wait();
612
0
  }
613
0
614
0
  {
615
0
    SynchronousTask task("ImageBridge ShutdownStep2 lock");
616
0
617
0
    RefPtr<Runnable> runnable = WrapRunnable(
618
0
      RefPtr<ImageBridgeChild>(this),
619
0
      &ImageBridgeChild::ShutdownStep2,
620
0
      &task);
621
0
    GetMessageLoop()->PostTask(runnable.forget());
622
0
623
0
    task.Wait();
624
0
  }
625
0
}
626
627
void
628
ImageBridgeChild::InitSameProcess(uint32_t aNamespace)
629
0
{
630
0
  NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
631
0
632
0
  MOZ_ASSERT(!sImageBridgeChildSingleton);
633
0
  MOZ_ASSERT(!sImageBridgeChildThread);
634
0
635
0
  sImageBridgeChildThread = new Thread("ImageBridgeChild");
636
0
  if (!sImageBridgeChildThread->IsRunning()) {
637
0
    sImageBridgeChildThread->Start();
638
0
  }
639
0
640
0
  RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
641
0
  RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess();
642
0
643
0
  RefPtr<Runnable> runnable = WrapRunnable(
644
0
    child,
645
0
    &ImageBridgeChild::BindSameProcess,
646
0
    parent);
647
0
  child->GetMessageLoop()->PostTask(runnable.forget());
648
0
649
0
  // Assign this after so other threads can't post messages before we connect to IPDL.
650
0
  {
651
0
    StaticMutexAutoLock lock(sImageBridgeSingletonLock);
652
0
    sImageBridgeChildSingleton = child;
653
0
  }
654
0
}
655
656
/* static */ void
657
ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
658
0
{
659
0
  MOZ_ASSERT(NS_IsMainThread());
660
0
  MOZ_ASSERT(!sImageBridgeChildSingleton);
661
0
  MOZ_ASSERT(!sImageBridgeChildThread);
662
0
663
0
  sImageBridgeChildThread = new Thread("ImageBridgeChild");
664
0
  if (!sImageBridgeChildThread->IsRunning()) {
665
0
    sImageBridgeChildThread->Start();
666
0
  }
667
0
668
0
  RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
669
0
670
0
  MessageLoop* loop = child->GetMessageLoop();
671
0
  loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
672
0
    "layers::ImageBridgeChild::Bind",
673
0
    child,
674
0
    &ImageBridgeChild::Bind,
675
0
    std::move(aEndpoint)));
676
0
677
0
  // Assign this after so other threads can't post messages before we connect to IPDL.
678
0
  {
679
0
    StaticMutexAutoLock lock(sImageBridgeSingletonLock);
680
0
    sImageBridgeChildSingleton = child;
681
0
  }
682
0
}
683
684
bool InImageBridgeChildThread()
685
0
{
686
0
  return sImageBridgeChildThread &&
687
0
    sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
688
0
}
689
690
MessageLoop * ImageBridgeChild::GetMessageLoop() const
691
0
{
692
0
  return sImageBridgeChildThread ? sImageBridgeChildThread->message_loop() : nullptr;
693
0
}
694
695
/* static */ void
696
ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier)
697
0
{
698
0
  if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
699
0
    child->UpdateTextureFactoryIdentifier(aIdentifier);
700
0
  }
701
0
}
702
703
void
704
ImageBridgeChild::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aIdentifier)
705
0
{
706
0
  // ImageHost is incompatible between WebRender enabled and WebRender disabled.
707
0
  // Then drop all ImageContainers' ImageClients during disabling WebRender.
708
0
  bool disablingWebRender = GetCompositorBackendType() == LayersBackend::LAYERS_WR &&
709
0
                            aIdentifier.mParentBackend != LayersBackend::LAYERS_WR;
710
0
  // D3DTexture might become obsolte. To prevent to use obsoleted D3DTexture,
711
0
  // drop all ImageContainers' ImageClients.
712
0
713
0
  bool needsDrop = disablingWebRender;
714
0
715
#if defined(XP_WIN)
716
  RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice();
717
  needsDrop |= !!mImageDevice &&
718
               mImageDevice != device &&
719
               GetCompositorBackendType() == LayersBackend::LAYERS_D3D11;
720
  mImageDevice = device;
721
#endif
722
723
0
  IdentifyTextureHost(aIdentifier);
724
0
  if (needsDrop) {
725
0
    nsTArray<RefPtr<ImageContainerListener> > listeners;
726
0
    {
727
0
      MutexAutoLock lock(mContainerMapLock);
728
0
      for (const auto& entry : mImageContainerListeners) {
729
0
        listeners.AppendElement(entry.second);
730
0
      }
731
0
    }
732
0
    // Drop ImageContainer's ImageClient whithout holding mContainerMapLock to avoid deadlock.
733
0
    for (auto container : listeners) {
734
0
      container->DropImageClient();
735
0
    }
736
0
  }
737
0
}
738
739
RefPtr<ImageClient>
740
ImageBridgeChild::CreateImageClient(CompositableType aType,
741
                                    ImageContainer* aImageContainer)
742
0
{
743
0
  if (InImageBridgeChildThread()) {
744
0
    return CreateImageClientNow(aType, aImageContainer);
745
0
  }
746
0
747
0
  SynchronousTask task("CreateImageClient Lock");
748
0
749
0
  RefPtr<ImageClient> result = nullptr;
750
0
751
0
  RefPtr<Runnable> runnable = WrapRunnable(
752
0
    RefPtr<ImageBridgeChild>(this),
753
0
    &ImageBridgeChild::CreateImageClientSync,
754
0
    &task,
755
0
    &result,
756
0
    aType,
757
0
    aImageContainer);
758
0
  GetMessageLoop()->PostTask(runnable.forget());
759
0
760
0
  task.Wait();
761
0
762
0
  return result;
763
0
}
764
765
RefPtr<ImageClient>
766
ImageBridgeChild::CreateImageClientNow(CompositableType aType,
767
                                       ImageContainer* aImageContainer)
768
0
{
769
0
  MOZ_ASSERT(InImageBridgeChildThread());
770
0
  if (!CanSend()) {
771
0
    return nullptr;
772
0
  }
773
0
774
0
  RefPtr<ImageClient> client = ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
775
0
  MOZ_ASSERT(client, "failed to create ImageClient");
776
0
  if (client) {
777
0
    client->Connect(aImageContainer);
778
0
  }
779
0
  return client;
780
0
}
781
782
already_AddRefed<CanvasClient>
783
ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType,
784
                                     TextureFlags aFlag)
785
0
{
786
0
  if (InImageBridgeChildThread()) {
787
0
    return CreateCanvasClientNow(aType, aFlag);
788
0
  }
789
0
790
0
  SynchronousTask task("CreateCanvasClient Lock");
791
0
792
0
  // RefPtrs on arguments are not needed since this dispatches synchronously.
793
0
  RefPtr<CanvasClient> result = nullptr;
794
0
  RefPtr<Runnable> runnable = WrapRunnable(
795
0
    RefPtr<ImageBridgeChild>(this),
796
0
    &ImageBridgeChild::CreateCanvasClientSync,
797
0
    &task,
798
0
    aType,
799
0
    aFlag,
800
0
    &result);
801
0
  GetMessageLoop()->PostTask(runnable.forget());
802
0
803
0
  task.Wait();
804
0
805
0
  return result.forget();
806
0
}
807
808
already_AddRefed<CanvasClient>
809
ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType,
810
                                        TextureFlags aFlag)
811
0
{
812
0
  RefPtr<CanvasClient> client
813
0
    = CanvasClient::CreateCanvasClient(aType, this, aFlag);
814
0
  MOZ_ASSERT(client, "failed to create CanvasClient");
815
0
  if (client) {
816
0
    client->Connect();
817
0
  }
818
0
  return client.forget();
819
0
}
820
821
bool
822
ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
823
                                   ipc::SharedMemory::SharedMemoryType aType,
824
                                   ipc::Shmem* aShmem)
825
0
{
826
0
  if (!InImageBridgeChildThread()) {
827
0
    return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe
828
0
  }
829
0
830
0
  if (!CanSend()) {
831
0
    return false;
832
0
  }
833
0
  return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
834
0
}
835
836
bool
837
ImageBridgeChild::AllocShmem(size_t aSize,
838
                             ipc::SharedMemory::SharedMemoryType aType,
839
                             ipc::Shmem* aShmem)
840
0
{
841
0
  if (!InImageBridgeChildThread()) {
842
0
    return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe
843
0
  }
844
0
845
0
  if (!CanSend()) {
846
0
    return false;
847
0
  }
848
0
  return PImageBridgeChild::AllocShmem(aSize, aType, aShmem);
849
0
}
850
851
// NewRunnableFunction accepts a limited number of parameters so we need a
852
// struct here
853
struct AllocShmemParams {
854
  size_t mSize;
855
  ipc::SharedMemory::SharedMemoryType mType;
856
  ipc::Shmem* mShmem;
857
  bool mUnsafe;
858
  bool mSuccess;
859
};
860
861
void
862
ImageBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, AllocShmemParams* aParams)
863
0
{
864
0
  AutoCompleteTask complete(aTask);
865
0
866
0
  if (!CanSend()) {
867
0
    return;
868
0
  }
869
0
870
0
  bool ok = false;
871
0
  if (aParams->mUnsafe) {
872
0
    ok = AllocUnsafeShmem(aParams->mSize, aParams->mType, aParams->mShmem);
873
0
  } else {
874
0
    ok = AllocShmem(aParams->mSize, aParams->mType, aParams->mShmem);
875
0
  }
876
0
  aParams->mSuccess = ok;
877
0
}
878
879
bool
880
ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize,
881
                                             SharedMemory::SharedMemoryType aType,
882
                                             ipc::Shmem* aShmem,
883
                                             bool aUnsafe)
884
0
{
885
0
  SynchronousTask task("AllocatorProxy alloc");
886
0
887
0
  AllocShmemParams params = {
888
0
    aSize, aType, aShmem, aUnsafe, false
889
0
  };
890
0
891
0
  RefPtr<Runnable> runnable = WrapRunnable(
892
0
    RefPtr<ImageBridgeChild>(this),
893
0
    &ImageBridgeChild::ProxyAllocShmemNow,
894
0
    &task,
895
0
    &params);
896
0
  GetMessageLoop()->PostTask(runnable.forget());
897
0
898
0
  task.Wait();
899
0
900
0
  return params.mSuccess;
901
0
}
902
903
void
904
ImageBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask,
905
                                       ipc::Shmem* aShmem,
906
                                       bool* aResult)
907
0
{
908
0
  AutoCompleteTask complete(aTask);
909
0
910
0
  if (!CanSend()) {
911
0
    return;
912
0
  }
913
0
  *aResult = DeallocShmem(*aShmem);
914
0
}
915
916
bool
917
ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
918
0
{
919
0
  if (InImageBridgeChildThread()) {
920
0
    if (!CanSend()) {
921
0
      return false;
922
0
    }
923
0
    return PImageBridgeChild::DeallocShmem(aShmem);
924
0
  }
925
0
926
0
  // If we can't post a task, then we definitely cannot send, so there's
927
0
  // no reason to queue up this send.
928
0
  if (!CanPostTask()) {
929
0
    return false;
930
0
  }
931
0
932
0
  SynchronousTask task("AllocatorProxy Dealloc");
933
0
  bool result = false;
934
0
935
0
  RefPtr<Runnable> runnable = WrapRunnable(
936
0
    RefPtr<ImageBridgeChild>(this),
937
0
    &ImageBridgeChild::ProxyDeallocShmemNow,
938
0
    &task,
939
0
    &aShmem,
940
0
    &result);
941
0
  GetMessageLoop()->PostTask(runnable.forget());
942
0
943
0
  task.Wait();
944
0
  return result;
945
0
}
946
947
PTextureChild*
948
ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
949
                                     const ReadLockDescriptor&,
950
                                     const LayersBackend&,
951
                                     const TextureFlags&,
952
                                     const uint64_t& aSerial,
953
                                     const wr::MaybeExternalImageId& aExternalImageId)
954
0
{
955
0
  MOZ_ASSERT(CanSend());
956
0
  return TextureClient::CreateIPDLActor();
957
0
}
958
959
bool
960
ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
961
0
{
962
0
  return TextureClient::DestroyIPDLActor(actor);
963
0
}
964
965
PMediaSystemResourceManagerChild*
966
ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
967
0
{
968
0
  MOZ_ASSERT(CanSend());
969
0
  return new mozilla::media::MediaSystemResourceManagerChild();
970
0
}
971
972
bool
973
ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
974
0
{
975
0
  MOZ_ASSERT(aActor);
976
0
  delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
977
0
  return true;
978
0
}
979
980
mozilla::ipc::IPCResult
981
ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
982
0
{
983
0
  for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
984
0
    const AsyncParentMessageData& message = aMessages[i];
985
0
986
0
    switch (message.type()) {
987
0
      case AsyncParentMessageData::TOpNotifyNotUsed: {
988
0
        const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
989
0
        NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
990
0
        break;
991
0
      }
992
0
      default:
993
0
        NS_ERROR("unknown AsyncParentMessageData type");
994
0
        return IPC_FAIL_NO_REASON(this);
995
0
    }
996
0
  }
997
0
  return IPC_OK();
998
0
}
999
1000
RefPtr<ImageContainerListener>
1001
ImageBridgeChild::FindListener(const CompositableHandle& aHandle)
1002
0
{
1003
0
  RefPtr<ImageContainerListener> listener;
1004
0
  MutexAutoLock lock(mContainerMapLock);
1005
0
  auto it = mImageContainerListeners.find(aHandle.Value());
1006
0
  if (it != mImageContainerListeners.end()) {
1007
0
    listener = it->second;
1008
0
  }
1009
0
  return listener;
1010
0
}
1011
1012
mozilla::ipc::IPCResult
1013
ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
1014
0
{
1015
0
  for (auto& n : aNotifications) {
1016
0
    RefPtr<ImageContainerListener> listener = FindListener(n.compositable());
1017
0
    if (listener) {
1018
0
      listener->NotifyComposite(n);
1019
0
    }
1020
0
  }
1021
0
  return IPC_OK();
1022
0
}
1023
1024
mozilla::ipc::IPCResult
1025
ImageBridgeChild::RecvReportFramesDropped(const CompositableHandle& aHandle, const uint32_t& aFrames)
1026
0
{
1027
0
  RefPtr<ImageContainerListener> listener = FindListener(aHandle);
1028
0
  if (listener) {
1029
0
    listener->NotifyDropped(aFrames);
1030
0
  }
1031
0
1032
0
  return IPC_OK();
1033
0
}
1034
1035
PTextureChild*
1036
ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
1037
                                const ReadLockDescriptor& aReadLock,
1038
                                LayersBackend aLayersBackend,
1039
                                TextureFlags aFlags,
1040
                                uint64_t aSerial,
1041
                                wr::MaybeExternalImageId& aExternalImageId,
1042
                                nsIEventTarget* aTarget)
1043
0
{
1044
0
  MOZ_ASSERT(CanSend());
1045
0
  return SendPTextureConstructor(aSharedData, aReadLock, aLayersBackend, aFlags, aSerial, aExternalImageId);
1046
0
}
1047
1048
static bool
1049
IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op)
1050
0
{
1051
0
  if (aTxn->Finished()) {
1052
0
    return false;
1053
0
  }
1054
0
1055
0
  aTxn->mDestroyedActors.AppendElement(op);
1056
0
  return true;
1057
0
}
1058
1059
bool
1060
ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture)
1061
0
{
1062
0
  return IBCAddOpDestroy(mTxn, OpDestroy(aTexture));
1063
0
}
1064
1065
bool
1066
ImageBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle)
1067
0
{
1068
0
  return IBCAddOpDestroy(mTxn, OpDestroy(aHandle));
1069
0
}
1070
1071
void
1072
ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
1073
                                                TextureClient* aTexture)
1074
0
{
1075
0
  MOZ_ASSERT(CanSend());
1076
0
  MOZ_ASSERT(aTexture);
1077
0
  MOZ_ASSERT(aTexture->IsSharedWithCompositor());
1078
0
  MOZ_ASSERT(aCompositable->IsConnected());
1079
0
  if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) {
1080
0
    return;
1081
0
  }
1082
0
1083
0
  mTxn->AddNoSwapEdit(CompositableOperation(
1084
0
    aCompositable->GetIPCHandle(),
1085
0
    OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
1086
0
}
1087
1088
bool ImageBridgeChild::IsSameProcess() const
1089
0
{
1090
0
  return OtherPid() == base::GetCurrentProcId();
1091
0
}
1092
1093
bool
1094
ImageBridgeChild::CanPostTask() const
1095
0
{
1096
0
  // During shutdown, the cycle collector may free objects that are holding a
1097
0
  // reference to ImageBridgeChild. Since this happens on the main thread,
1098
0
  // ImageBridgeChild will attempt to post a task to the ImageBridge thread.
1099
0
  // However the thread manager has already been shut down, so the task cannot
1100
0
  // post.
1101
0
  //
1102
0
  // It's okay if this races. We only care about the shutdown case where
1103
0
  // everything's happening on the main thread. Even if it races outside of
1104
0
  // shutdown, it's still harmless to post the task, since the task must
1105
0
  // check CanSend().
1106
0
  return !mDestroyed;
1107
0
}
1108
1109
void
1110
ImageBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle)
1111
0
{
1112
0
  if (!InImageBridgeChildThread()) {
1113
0
    // If we can't post a task, then we definitely cannot send, so there's
1114
0
    // no reason to queue up this send.
1115
0
    if (!CanPostTask()) {
1116
0
      return;
1117
0
    }
1118
0
1119
0
    RefPtr<Runnable> runnable = WrapRunnable(
1120
0
      RefPtr<ImageBridgeChild>(this),
1121
0
      &ImageBridgeChild::ReleaseCompositable,
1122
0
      aHandle);
1123
0
    GetMessageLoop()->PostTask(runnable.forget());
1124
0
    return;
1125
0
  }
1126
0
1127
0
  if (!CanSend()) {
1128
0
    return;
1129
0
  }
1130
0
1131
0
  if (!DestroyInTransaction(aHandle)) {
1132
0
    SendReleaseCompositable(aHandle);
1133
0
  }
1134
0
1135
0
  {
1136
0
    MutexAutoLock lock(mContainerMapLock);
1137
0
    mImageContainerListeners.erase(aHandle.Value());
1138
0
  }
1139
0
}
1140
1141
bool
1142
ImageBridgeChild::CanSend() const
1143
0
{
1144
0
  MOZ_ASSERT(InImageBridgeChildThread());
1145
0
  return mCanSend;
1146
0
}
1147
1148
void
1149
ImageBridgeChild::HandleFatalError(const char* aMsg) const
1150
0
{
1151
0
  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
1152
0
}
1153
1154
wr::MaybeExternalImageId
1155
ImageBridgeChild::GetNextExternalImageId()
1156
0
{
1157
0
  static uint32_t sNextID = 1;
1158
0
  ++sNextID;
1159
0
  MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
1160
0
1161
0
  uint64_t imageId = mNamespace;
1162
0
  imageId = imageId << 32 | sNextID;
1163
0
  return Some(wr::ToExternalImageId(imageId));
1164
0
}
1165
1166
} // namespace layers
1167
} // namespace mozilla