Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/ipc/GPUProcessManager.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 "GPUProcessManager.h"
8
9
#include "gfxPrefs.h"
10
#include "GPUProcessHost.h"
11
#include "GPUProcessListener.h"
12
#include "mozilla/MemoryReportingProcess.h"
13
#include "mozilla/Sprintf.h"
14
#include "mozilla/StaticPtr.h"
15
#include "mozilla/StaticPrefs.h"
16
#include "mozilla/dom/ContentParent.h"
17
#include "mozilla/gfx/gfxVars.h"
18
#include "mozilla/layers/APZCTreeManagerChild.h"
19
#include "mozilla/layers/CompositorBridgeParent.h"
20
#include "mozilla/layers/CompositorManagerChild.h"
21
#include "mozilla/layers/CompositorManagerParent.h"
22
#include "mozilla/layers/CompositorOptions.h"
23
#include "mozilla/layers/ImageBridgeChild.h"
24
#include "mozilla/layers/ImageBridgeParent.h"
25
#include "mozilla/layers/InProcessCompositorSession.h"
26
#include "mozilla/layers/LayerTreeOwnerTracker.h"
27
#include "mozilla/layers/RemoteCompositorSession.h"
28
#include "mozilla/widget/PlatformWidgetTypes.h"
29
#include "nsAppRunner.h"
30
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
31
# include "mozilla/widget/CompositorWidgetChild.h"
32
#endif
33
#include "nsBaseWidget.h"
34
#include "nsContentUtils.h"
35
#include "VRManagerChild.h"
36
#include "VRManagerParent.h"
37
#include "VsyncBridgeChild.h"
38
#include "VsyncIOThreadHolder.h"
39
#include "VsyncSource.h"
40
#include "mozilla/dom/VideoDecoderManagerChild.h"
41
#include "mozilla/dom/VideoDecoderManagerParent.h"
42
#include "nsExceptionHandler.h"
43
#include "nsPrintfCString.h"
44
45
#if defined(MOZ_WIDGET_ANDROID)
46
#include "mozilla/widget/AndroidUiThread.h"
47
#include "mozilla/layers/UiCompositorControllerChild.h"
48
#endif // defined(MOZ_WIDGET_ANDROID)
49
50
namespace mozilla {
51
namespace gfx {
52
53
using namespace mozilla::layers;
54
55
enum class FallbackType : uint32_t
56
{
57
  NONE = 0,
58
  DECODINGDISABLED,
59
  DISABLED,
60
};
61
62
static StaticAutoPtr<GPUProcessManager> sSingleton;
63
64
GPUProcessManager*
65
GPUProcessManager::Get()
66
0
{
67
0
  return sSingleton;
68
0
}
69
70
void
71
GPUProcessManager::Initialize()
72
0
{
73
0
  MOZ_ASSERT(XRE_IsParentProcess());
74
0
  sSingleton = new GPUProcessManager();
75
0
}
76
77
void
78
GPUProcessManager::Shutdown()
79
0
{
80
0
  sSingleton = nullptr;
81
0
}
82
83
GPUProcessManager::GPUProcessManager()
84
 : mTaskFactory(this),
85
   mNextNamespace(0),
86
   mIdNamespace(0),
87
   mResourceId(0),
88
   mNumProcessAttempts(0),
89
   mDeviceResetCount(0),
90
   mProcess(nullptr),
91
   mProcessToken(0),
92
   mGPUChild(nullptr)
93
0
{
94
0
  MOZ_COUNT_CTOR(GPUProcessManager);
95
0
96
0
  mIdNamespace = AllocateNamespace();
97
0
  mObserver = new Observer(this);
98
0
  nsContentUtils::RegisterShutdownObserver(mObserver);
99
0
100
0
  mDeviceResetLastTime = TimeStamp::Now();
101
0
102
0
  LayerTreeOwnerTracker::Initialize();
103
0
}
104
105
GPUProcessManager::~GPUProcessManager()
106
0
{
107
0
  MOZ_COUNT_DTOR(GPUProcessManager);
108
0
109
0
  LayerTreeOwnerTracker::Shutdown();
110
0
111
0
  // The GPU process should have already been shut down.
112
0
  MOZ_ASSERT(!mProcess && !mGPUChild);
113
0
114
0
  // We should have already removed observers.
115
0
  MOZ_ASSERT(!mObserver);
116
0
}
117
118
NS_IMPL_ISUPPORTS(GPUProcessManager::Observer, nsIObserver);
119
120
GPUProcessManager::Observer::Observer(GPUProcessManager* aManager)
121
 : mManager(aManager)
122
0
{
123
0
}
124
125
NS_IMETHODIMP
126
GPUProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
127
0
{
128
0
  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
129
0
    mManager->OnXPCOMShutdown();
130
0
  }
131
0
  return NS_OK;
132
0
}
133
134
void
135
GPUProcessManager::OnXPCOMShutdown()
136
0
{
137
0
  if (mObserver) {
138
0
    nsContentUtils::UnregisterShutdownObserver(mObserver);
139
0
    mObserver = nullptr;
140
0
  }
141
0
142
0
  CleanShutdown();
143
0
}
144
145
void
146
GPUProcessManager::LaunchGPUProcess()
147
0
{
148
0
  if (mProcess) {
149
0
    return;
150
0
  }
151
0
152
0
  // Start the Vsync I/O thread so can use it as soon as the process launches.
153
0
  EnsureVsyncIOThread();
154
0
155
0
  mNumProcessAttempts++;
156
0
157
0
  std::vector<std::string> extraArgs;
158
0
  nsCString parentBuildID(mozilla::PlatformBuildID());
159
0
  extraArgs.push_back("-parentBuildID");
160
0
  extraArgs.push_back(parentBuildID.get());
161
0
162
0
  // The subprocess is launched asynchronously, so we wait for a callback to
163
0
  // acquire the IPDL actor.
164
0
  mProcess = new GPUProcessHost(this);
165
0
  if (!mProcess->Launch(extraArgs)) {
166
0
    DisableGPUProcess("Failed to launch GPU process");
167
0
  }
168
0
}
169
170
void
171
GPUProcessManager::DisableGPUProcess(const char* aMessage)
172
0
{
173
0
  if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
174
0
    return;
175
0
  }
176
0
177
0
  gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, aMessage);
178
0
  gfxCriticalNote << aMessage;
179
0
180
0
  gfxPlatform::NotifyGPUProcessDisabled();
181
0
182
0
  Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
183
0
                        uint32_t(FallbackType::DISABLED));
184
0
185
0
  DestroyProcess();
186
0
  ShutdownVsyncIOThread();
187
0
188
0
  // We may have been in the middle of guaranteeing our various services are
189
0
  // available when one failed. Some callers may fallback to using the same
190
0
  // process equivalent, and we need to make sure those services are setup
191
0
  // correctly. We cannot re-enter DisableGPUProcess from this call because we
192
0
  // know that it is disabled in the config above.
193
0
  EnsureProtocolsReady();
194
0
195
0
  // If we disable the GPU process during reinitialization after a previous
196
0
  // crash, then we need to tell the content processes again, because they
197
0
  // need to rebind to the UI process.
198
0
  HandleProcessLost();
199
0
}
200
201
bool
202
GPUProcessManager::EnsureGPUReady()
203
0
{
204
0
  if (mProcess && !mProcess->IsConnected()) {
205
0
    if (!mProcess->WaitForLaunch()) {
206
0
      // If this fails, we should have fired OnProcessLaunchComplete and
207
0
      // removed the process.
208
0
      MOZ_ASSERT(!mProcess && !mGPUChild);
209
0
      return false;
210
0
    }
211
0
  }
212
0
213
0
  if (mGPUChild) {
214
0
    if (mGPUChild->EnsureGPUReady()) {
215
0
      return true;
216
0
    }
217
0
218
0
    // If the initialization above fails, we likely have a GPU process teardown
219
0
    // waiting in our message queue (or will soon). We need to ensure we don't
220
0
    // restart it later because if we fail here, our callers assume they should
221
0
    // fall back to a combined UI/GPU process. This also ensures our internal
222
0
    // state is consistent (e.g. process token is reset).
223
0
    DisableGPUProcess("Failed to initialize GPU process");
224
0
  }
225
0
226
0
  return false;
227
0
}
228
229
void
230
GPUProcessManager::EnsureProtocolsReady()
231
0
{
232
0
  EnsureCompositorManagerChild();
233
0
  EnsureImageBridgeChild();
234
0
  EnsureVRManager();
235
0
}
236
237
void
238
GPUProcessManager::EnsureCompositorManagerChild()
239
0
{
240
0
  bool gpuReady = EnsureGPUReady();
241
0
  if (CompositorManagerChild::IsInitialized(mProcessToken)) {
242
0
    return;
243
0
  }
244
0
245
0
  if (!gpuReady) {
246
0
    CompositorManagerChild::InitSameProcess(AllocateNamespace(), mProcessToken);
247
0
    return;
248
0
  }
249
0
250
0
  ipc::Endpoint<PCompositorManagerParent> parentPipe;
251
0
  ipc::Endpoint<PCompositorManagerChild> childPipe;
252
0
  nsresult rv = PCompositorManager::CreateEndpoints(
253
0
    mGPUChild->OtherPid(),
254
0
    base::GetCurrentProcId(),
255
0
    &parentPipe,
256
0
    &childPipe);
257
0
  if (NS_FAILED(rv)) {
258
0
    DisableGPUProcess("Failed to create PCompositorManager endpoints");
259
0
    return;
260
0
  }
261
0
262
0
  mGPUChild->SendInitCompositorManager(std::move(parentPipe));
263
0
  CompositorManagerChild::Init(std::move(childPipe), AllocateNamespace(),
264
0
                               mProcessToken);
265
0
}
266
267
void
268
GPUProcessManager::EnsureImageBridgeChild()
269
0
{
270
0
  if (ImageBridgeChild::GetSingleton()) {
271
0
    return;
272
0
  }
273
0
274
0
  if (!EnsureGPUReady()) {
275
0
    ImageBridgeChild::InitSameProcess(AllocateNamespace());
276
0
    return;
277
0
  }
278
0
279
0
  ipc::Endpoint<PImageBridgeParent> parentPipe;
280
0
  ipc::Endpoint<PImageBridgeChild> childPipe;
281
0
  nsresult rv = PImageBridge::CreateEndpoints(
282
0
    mGPUChild->OtherPid(),
283
0
    base::GetCurrentProcId(),
284
0
    &parentPipe,
285
0
    &childPipe);
286
0
  if (NS_FAILED(rv)) {
287
0
    DisableGPUProcess("Failed to create PImageBridge endpoints");
288
0
    return;
289
0
  }
290
0
291
0
  mGPUChild->SendInitImageBridge(std::move(parentPipe));
292
0
  ImageBridgeChild::InitWithGPUProcess(std::move(childPipe), AllocateNamespace());
293
0
}
294
295
void
296
GPUProcessManager::EnsureVRManager()
297
0
{
298
0
  if (VRManagerChild::IsCreated()) {
299
0
    return;
300
0
  }
301
0
302
0
  if (!EnsureGPUReady()) {
303
0
    VRManagerChild::InitSameProcess();
304
0
    return;
305
0
  }
306
0
307
0
  ipc::Endpoint<PVRManagerParent> parentPipe;
308
0
  ipc::Endpoint<PVRManagerChild> childPipe;
309
0
  nsresult rv = PVRManager::CreateEndpoints(
310
0
    mGPUChild->OtherPid(),
311
0
    base::GetCurrentProcId(),
312
0
    &parentPipe,
313
0
    &childPipe);
314
0
  if (NS_FAILED(rv)) {
315
0
    DisableGPUProcess("Failed to create PVRManager endpoints");
316
0
    return;
317
0
  }
318
0
319
0
  mGPUChild->SendInitVRManager(std::move(parentPipe));
320
0
  VRManagerChild::InitWithGPUProcess(std::move(childPipe));
321
0
}
322
323
#if defined(MOZ_WIDGET_ANDROID)
324
already_AddRefed<UiCompositorControllerChild>
325
GPUProcessManager::CreateUiCompositorController(nsBaseWidget* aWidget, const LayersId aId)
326
{
327
  RefPtr<UiCompositorControllerChild> result;
328
329
  if (!EnsureGPUReady()) {
330
    result = UiCompositorControllerChild::CreateForSameProcess(aId);
331
  } else {
332
    ipc::Endpoint<PUiCompositorControllerParent> parentPipe;
333
    ipc::Endpoint<PUiCompositorControllerChild> childPipe;
334
    nsresult rv = PUiCompositorController::CreateEndpoints(
335
      mGPUChild->OtherPid(),
336
      base::GetCurrentProcId(),
337
      &parentPipe,
338
      &childPipe);
339
    if (NS_FAILED(rv)) {
340
      DisableGPUProcess("Failed to create PUiCompositorController endpoints");
341
      return nullptr;
342
    }
343
344
    mGPUChild->SendInitUiCompositorController(aId, std::move(parentPipe));
345
    result = UiCompositorControllerChild::CreateForGPUProcess(mProcessToken, std::move(childPipe));
346
  }
347
  if (result) {
348
    result->SetBaseWidget(aWidget);
349
  }
350
  return result.forget();
351
}
352
#endif // defined(MOZ_WIDGET_ANDROID)
353
354
void
355
GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
356
0
{
357
0
  MOZ_ASSERT(mProcess && mProcess == aHost);
358
0
359
0
  if (!mProcess->IsConnected()) {
360
0
    DisableGPUProcess("Failed to connect GPU process");
361
0
    return;
362
0
  }
363
0
364
0
  mGPUChild = mProcess->GetActor();
365
0
  mProcessToken = mProcess->GetProcessToken();
366
0
367
0
  Endpoint<PVsyncBridgeParent> vsyncParent;
368
0
  Endpoint<PVsyncBridgeChild> vsyncChild;
369
0
  nsresult rv = PVsyncBridge::CreateEndpoints(
370
0
    mGPUChild->OtherPid(),
371
0
    base::GetCurrentProcId(),
372
0
    &vsyncParent,
373
0
    &vsyncChild);
374
0
  if (NS_FAILED(rv)) {
375
0
    DisableGPUProcess("Failed to create PVsyncBridge endpoints");
376
0
    return;
377
0
  }
378
0
379
0
  mVsyncBridge = VsyncBridgeChild::Create(mVsyncIOThread, mProcessToken, std::move(vsyncChild));
380
0
  mGPUChild->SendInitVsyncBridge(std::move(vsyncParent));
381
0
382
0
  CrashReporter::AnnotateCrashReport(
383
0
    CrashReporter::Annotation::GPUProcessStatus, NS_LITERAL_CSTRING("Running"));
384
0
385
0
  CrashReporter::AnnotateCrashReport(
386
0
    CrashReporter::Annotation::GPUProcessLaunchCount,
387
0
    static_cast<int>(mNumProcessAttempts));
388
0
}
389
390
static bool
391
ShouldLimitDeviceResets(uint32_t count, int32_t deltaMilliseconds)
392
0
{
393
0
  // We decide to limit by comparing the amount of resets that have happened
394
0
  // and time since the last reset to two prefs.
395
0
  int32_t timeLimit = gfxPrefs::DeviceResetThresholdMilliseconds();
396
0
  int32_t countLimit = gfxPrefs::DeviceResetLimitCount();
397
0
398
0
  bool hasTimeLimit = timeLimit >= 0;
399
0
  bool hasCountLimit = countLimit >= 0;
400
0
401
0
  bool triggeredTime = deltaMilliseconds < timeLimit;
402
0
  bool triggeredCount = count > (uint32_t)countLimit;
403
0
404
0
  // If we have both prefs set then it needs to trigger both limits,
405
0
  // otherwise we only test the pref that is set or none
406
0
  if (hasTimeLimit && hasCountLimit) {
407
0
    return triggeredTime && triggeredCount;
408
0
  } else if (hasTimeLimit) {
409
0
    return triggeredTime;
410
0
  } else if (hasCountLimit) {
411
0
    return triggeredCount;
412
0
  }
413
0
414
0
  return false;
415
0
}
416
417
void
418
GPUProcessManager::ResetCompositors()
419
0
{
420
0
  // Note: this will recreate devices in addition to recreating compositors.
421
0
  // This isn't optimal, but this is only used on linux where acceleration
422
0
  // isn't enabled by default, and this way we don't need a new code path.
423
0
  SimulateDeviceReset();
424
0
}
425
426
void
427
GPUProcessManager::SimulateDeviceReset()
428
0
{
429
0
  // Make sure we rebuild environment and configuration for accelerated features.
430
0
  gfxPlatform::GetPlatform()->CompositorUpdated();
431
0
432
0
  if (mProcess) {
433
0
    GPUDeviceData data;
434
0
    if (mGPUChild->SendSimulateDeviceReset(&data)) {
435
0
      gfxPlatform::GetPlatform()->ImportGPUDeviceData(data);
436
0
    }
437
0
    OnRemoteProcessDeviceReset(mProcess);
438
0
  } else {
439
0
    OnInProcessDeviceReset();
440
0
  }
441
0
}
442
443
void
444
GPUProcessManager::DisableWebRender(wr::WebRenderError aError)
445
0
{
446
0
  if (!gfx::gfxVars::UseWebRender()) {
447
0
    return;
448
0
  }
449
0
  // Disable WebRender
450
0
  if (aError == wr::WebRenderError::INITIALIZE) {
451
0
    gfx::gfxConfig::GetFeature(gfx::Feature::WEBRENDER).ForceDisable(
452
0
      gfx::FeatureStatus::Unavailable,
453
0
      "WebRender initialization failed",
454
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_INITIALIZE"));
455
0
  } else if (aError == wr::WebRenderError::MAKE_CURRENT) {
456
0
    gfx::gfxConfig::GetFeature(gfx::Feature::WEBRENDER).ForceDisable(
457
0
      gfx::FeatureStatus::Unavailable,
458
0
      "Failed to make render context current",
459
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_MAKE_CURRENT"));
460
0
  } else if (aError == wr::WebRenderError::RENDER) {
461
0
    gfx::gfxConfig::GetFeature(gfx::Feature::WEBRENDER).ForceDisable(
462
0
      gfx::FeatureStatus::Unavailable,
463
0
      "Failed to render WebRender",
464
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_RENDER"));
465
0
  } else {
466
0
    MOZ_ASSERT_UNREACHABLE("Invalid value");
467
0
  }
468
0
  gfx::gfxVars::SetUseWebRender(false);
469
0
470
0
  if (mProcess) {
471
0
    OnRemoteProcessDeviceReset(mProcess);
472
0
  } else {
473
0
    OnInProcessDeviceReset();
474
0
  }
475
0
}
476
477
void
478
GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError)
479
0
{
480
0
  DisableWebRender(aError);
481
0
}
482
483
void
484
GPUProcessManager::OnInProcessDeviceReset()
485
0
{
486
0
  RebuildInProcessSessions();
487
0
  NotifyListenersOnCompositeDeviceReset();
488
0
}
489
490
void
491
GPUProcessManager::OnRemoteProcessDeviceReset(GPUProcessHost* aHost)
492
0
{
493
0
  // Detect whether the device is resetting too quickly or too much
494
0
  // indicating that we should give up and use software
495
0
  mDeviceResetCount++;
496
0
497
0
  auto newTime = TimeStamp::Now();
498
0
  auto delta = (int32_t)(newTime - mDeviceResetLastTime).ToMilliseconds();
499
0
  mDeviceResetLastTime = newTime;
500
0
501
0
  if (ShouldLimitDeviceResets(mDeviceResetCount, delta)) {
502
0
    DestroyProcess();
503
0
    DisableGPUProcess("GPU processed experienced too many device resets");
504
0
505
0
    // Reaches the limited TDR attempts, fallback to software solution.
506
0
    gfxConfig::SetFailed(Feature::HW_COMPOSITING,
507
0
      FeatureStatus::Blocked,
508
0
      "Too many attemps of D3D11 creation, fallback to software solution.");
509
0
    gfxConfig::SetFailed(Feature::D3D11_COMPOSITING,
510
0
      FeatureStatus::Blocked,
511
0
      "Too many attemps of D3D11 creation, fallback to software solution.");
512
0
    gfxConfig::SetFailed(Feature::DIRECT2D,
513
0
      FeatureStatus::Blocked,
514
0
      "Too many attemps of D3D11 creation, fallback to software solution.");
515
0
516
0
    HandleProcessLost();
517
0
    return;
518
0
  }
519
0
520
0
  RebuildRemoteSessions();
521
0
  NotifyListenersOnCompositeDeviceReset();
522
0
}
523
524
void
525
GPUProcessManager::NotifyListenersOnCompositeDeviceReset()
526
0
{
527
0
  for (const auto& listener : mListeners) {
528
0
    listener->OnCompositorDeviceReset();
529
0
  }
530
0
}
531
532
void
533
GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
534
0
{
535
0
  MOZ_ASSERT(mProcess && mProcess == aHost);
536
0
537
0
  CompositorManagerChild::OnGPUProcessLost(aHost->GetProcessToken());
538
0
  DestroyProcess();
539
0
540
0
  if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestarts())) {
541
0
    char disableMessage[64];
542
0
    SprintfLiteral(disableMessage, "GPU process disabled after %d attempts",
543
0
                   mNumProcessAttempts);
544
0
    DisableGPUProcess(disableMessage);
545
0
  } else if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestartsWithDecoder()) &&
546
0
             mDecodeVideoOnGpuProcess) {
547
0
    mDecodeVideoOnGpuProcess = false;
548
0
    Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
549
0
                                     uint32_t(FallbackType::DECODINGDISABLED));
550
0
    HandleProcessLost();
551
0
  } else {
552
0
    Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
553
0
                                     uint32_t(FallbackType::NONE));
554
0
    HandleProcessLost();
555
0
  }
556
0
}
557
558
void
559
GPUProcessManager::HandleProcessLost()
560
0
{
561
0
  if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
562
0
    LaunchGPUProcess();
563
0
  }
564
0
565
0
  // The shutdown and restart sequence for the GPU process is as follows:
566
0
  //
567
0
  //  (1) The GPU process dies. IPDL will enqueue an ActorDestroy message on
568
0
  //      each channel owning a bridge to the GPU process, on the thread
569
0
  //      owning that channel.
570
0
  //
571
0
  //  (2) The first channel to process its ActorDestroy message will post a
572
0
  //      message to the main thread to call NotifyRemoteActorDestroyed on
573
0
  //      the GPUProcessManager, which calls OnProcessUnexpectedShutdown if
574
0
  //      it has not handled shutdown for this process yet.
575
0
  //
576
0
  //  (3) We then notify each widget that its session with the compositor is
577
0
  //      now invalid. The widget is responsible for destroying its layer
578
0
  //      manager and CompositorBridgeChild. Note that at this stage, not
579
0
  //      all actors may have received ActorDestroy yet. CompositorBridgeChild
580
0
  //      may attempt to send messages, and if this happens, it will probably
581
0
  //      report a MsgDropped error. This is okay.
582
0
  //
583
0
  //  (4) At this point, the UI process has a clean slate: no layers should
584
0
  //      exist for the old compositor. We may make a decision on whether or
585
0
  //      not to re-launch the GPU process. Currently, we do not relaunch it,
586
0
  //      and any new compositors will be created in-process and will default
587
0
  //      to software.
588
0
  //
589
0
  //  (5) Next we notify each ContentParent of the lost connection. It will
590
0
  //      request new endpoints from the GPUProcessManager and forward them
591
0
  //      to its ContentChild. The parent-side of these endpoints may come
592
0
  //      from the compositor thread of the UI process, or the compositor
593
0
  //      thread of the GPU process. However, no actual compositors should
594
0
  //      exist yet.
595
0
  //
596
0
  //  (6) Each ContentChild will receive new endpoints. It will destroy its
597
0
  //      Compositor/ImageBridgeChild singletons and recreate them, as well
598
0
  //      as invalidate all retained layers.
599
0
  //
600
0
  //  (7) In addition, each ContentChild will ask each of its TabChildren
601
0
  //      to re-request association with the compositor for the window
602
0
  //      owning the tab. The sequence of calls looks like:
603
0
  //        (a) [CONTENT] ContentChild::RecvReinitRendering
604
0
  //        (b) [CONTENT] TabChild::ReinitRendering
605
0
  //        (c) [CONTENT] TabChild::SendEnsureLayersConnected
606
0
  //        (d)      [UI] TabParent::RecvEnsureLayersConnected
607
0
  //        (e)      [UI] RenderFrameParent::EnsureLayersConnected
608
0
  //        (f)      [UI] CompositorBridgeChild::SendNotifyChildRecreated
609
0
  //
610
0
  //      Note that at step (e), RenderFrameParent will call GetLayerManager
611
0
  //      on the nsIWidget owning the tab. This step ensures that a compositor
612
0
  //      exists for the window. If we decided to launch a new GPU Process,
613
0
  //      at this point we block until the process has launched and we're
614
0
  //      able to create a new window compositor. Otherwise, if compositing
615
0
  //      is now in-process, this will simply create a new
616
0
  //      CompositorBridgeParent in the UI process. If there are multiple tabs
617
0
  //      in the same window, additional tabs will simply return the already-
618
0
  //      established compositor.
619
0
  //
620
0
  //      Finally, this step serves one other crucial function: tabs must be
621
0
  //      associated with a window compositor or else they can't forward
622
0
  //      layer transactions. So this step both ensures that a compositor
623
0
  //      exists, and that the tab can forward layers.
624
0
  //
625
0
  //  (8) Last, if the window had no remote tabs, step (7) will not have
626
0
  //      applied, and the window will not have a new compositor just yet.
627
0
  //      The next refresh tick and paint will ensure that one exists, again
628
0
  //      via nsIWidget::GetLayerManager.
629
0
  RebuildRemoteSessions();
630
0
631
0
  // Notify content. This will ensure that each content process re-establishes
632
0
  // a connection to the compositor thread (whether it's in-process or in a
633
0
  // newly launched GPU process).
634
0
  for (const auto& listener : mListeners) {
635
0
    listener->OnCompositorUnexpectedShutdown();
636
0
  }
637
0
}
638
639
void
640
GPUProcessManager::RebuildRemoteSessions()
641
0
{
642
0
  // Build a list of sessions to notify, since notification might delete
643
0
  // entries from the list.
644
0
  nsTArray<RefPtr<RemoteCompositorSession>> sessions;
645
0
  for (auto& session : mRemoteSessions) {
646
0
    sessions.AppendElement(session);
647
0
  }
648
0
649
0
  // Notify each widget that we have lost the GPU process. This will ensure
650
0
  // that each widget destroys its layer manager and CompositorBridgeChild.
651
0
  for (const auto& session : sessions) {
652
0
    session->NotifySessionLost();
653
0
  }
654
0
}
655
656
void
657
GPUProcessManager::RebuildInProcessSessions()
658
0
{
659
0
  // Build a list of sessions to notify, since notification might delete
660
0
  // entries from the list.
661
0
  nsTArray<RefPtr<InProcessCompositorSession>> sessions;
662
0
  for (auto& session : mInProcessSessions) {
663
0
    sessions.AppendElement(session);
664
0
  }
665
0
666
0
  // Notify each widget that we have lost the GPU process. This will ensure
667
0
  // that each widget destroys its layer manager and CompositorBridgeChild.
668
0
  for (const auto& session : sessions) {
669
0
    session->NotifySessionLost();
670
0
  }
671
0
}
672
673
void
674
GPUProcessManager::NotifyRemoteActorDestroyed(const uint64_t& aProcessToken)
675
0
{
676
0
  if (!NS_IsMainThread()) {
677
0
    RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod(
678
0
      &GPUProcessManager::NotifyRemoteActorDestroyed, aProcessToken);
679
0
    NS_DispatchToMainThread(task.forget());
680
0
    return;
681
0
  }
682
0
683
0
  if (mProcessToken != aProcessToken) {
684
0
    // This token is for an older process; we can safely ignore it.
685
0
    return;
686
0
  }
687
0
688
0
  // One of the bridged top-level actors for the GPU process has been
689
0
  // prematurely terminated, and we're receiving a notification. This
690
0
  // can happen if the ActorDestroy for a bridged protocol fires
691
0
  // before the ActorDestroy for PGPUChild.
692
0
  OnProcessUnexpectedShutdown(mProcess);
693
0
}
694
695
void
696
GPUProcessManager::CleanShutdown()
697
0
{
698
0
  DestroyProcess();
699
0
  mVsyncIOThread = nullptr;
700
0
}
701
702
void
703
GPUProcessManager::KillProcess()
704
0
{
705
0
  if (!mProcess) {
706
0
    return;
707
0
  }
708
0
709
0
  mProcess->KillProcess();
710
0
}
711
712
void
713
GPUProcessManager::DestroyProcess()
714
0
{
715
0
  if (!mProcess) {
716
0
    return;
717
0
  }
718
0
719
0
  mProcess->Shutdown();
720
0
  mProcessToken = 0;
721
0
  mProcess = nullptr;
722
0
  mGPUChild = nullptr;
723
0
  if (mVsyncBridge) {
724
0
    mVsyncBridge->Close();
725
0
    mVsyncBridge = nullptr;
726
0
  }
727
0
728
0
  CrashReporter::AnnotateCrashReport(
729
0
    CrashReporter::Annotation::GPUProcessStatus,
730
0
    NS_LITERAL_CSTRING("Destroyed"));
731
0
}
732
733
already_AddRefed<CompositorSession>
734
GPUProcessManager::CreateTopLevelCompositor(nsBaseWidget* aWidget,
735
                                            LayerManager* aLayerManager,
736
                                            CSSToLayoutDeviceScale aScale,
737
                                            const CompositorOptions& aOptions,
738
                                            bool aUseExternalSurfaceSize,
739
                                            const gfx::IntSize& aSurfaceSize,
740
                                            bool* aRetryOut)
741
0
{
742
0
  MOZ_ASSERT(aRetryOut);
743
0
744
0
  LayersId layerTreeId = AllocateLayerTreeId();
745
0
746
0
  EnsureProtocolsReady();
747
0
748
0
  RefPtr<CompositorSession> session;
749
0
750
0
  if (EnsureGPUReady()) {
751
0
    session = CreateRemoteSession(
752
0
      aWidget,
753
0
      aLayerManager,
754
0
      layerTreeId,
755
0
      aScale,
756
0
      aOptions,
757
0
      aUseExternalSurfaceSize,
758
0
      aSurfaceSize);
759
0
    if (!session) {
760
0
      // We couldn't create a remote compositor, so abort the process.
761
0
      DisableGPUProcess("Failed to create remote compositor");
762
0
      *aRetryOut = true;
763
0
      return nullptr;
764
0
    }
765
0
  } else {
766
0
    session = InProcessCompositorSession::Create(
767
0
      aWidget,
768
0
      aLayerManager,
769
0
      layerTreeId,
770
0
      aScale,
771
0
      aOptions,
772
0
      aUseExternalSurfaceSize,
773
0
      aSurfaceSize,
774
0
      AllocateNamespace());
775
0
  }
776
0
777
#if defined(MOZ_WIDGET_ANDROID)
778
  if (session) {
779
    // Nothing to do if controller gets a nullptr
780
    RefPtr<UiCompositorControllerChild> controller = CreateUiCompositorController(aWidget, session->RootLayerTreeId());
781
    session->SetUiCompositorControllerChild(controller);
782
  }
783
#endif // defined(MOZ_WIDGET_ANDROID)
784
785
0
  *aRetryOut = false;
786
0
  return session.forget();
787
0
}
788
789
RefPtr<CompositorSession>
790
GPUProcessManager::CreateRemoteSession(nsBaseWidget* aWidget,
791
                                       LayerManager* aLayerManager,
792
                                       const LayersId& aRootLayerTreeId,
793
                                       CSSToLayoutDeviceScale aScale,
794
                                       const CompositorOptions& aOptions,
795
                                       bool aUseExternalSurfaceSize,
796
                                       const gfx::IntSize& aSurfaceSize)
797
0
{
798
0
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
799
0
  CompositorWidgetInitData initData;
800
0
  aWidget->GetCompositorWidgetInitData(&initData);
801
0
802
0
  RefPtr<CompositorBridgeChild> child =
803
0
    CompositorManagerChild::CreateWidgetCompositorBridge(
804
0
      mProcessToken,
805
0
      aLayerManager,
806
0
      AllocateNamespace(),
807
0
      aScale,
808
0
      aOptions,
809
0
      aUseExternalSurfaceSize,
810
0
      aSurfaceSize);
811
0
  if (!child) {
812
0
    gfxCriticalNote << "Failed to create CompositorBridgeChild";
813
0
    return nullptr;
814
0
  }
815
0
816
0
  RefPtr<CompositorVsyncDispatcher> dispatcher = aWidget->GetCompositorVsyncDispatcher();
817
0
  RefPtr<CompositorWidgetVsyncObserver> observer =
818
0
    new CompositorWidgetVsyncObserver(mVsyncBridge, aRootLayerTreeId);
819
0
820
0
  CompositorWidgetChild* widget = new CompositorWidgetChild(dispatcher, observer);
821
0
  if (!child->SendPCompositorWidgetConstructor(widget, initData)) {
822
0
    return nullptr;
823
0
  }
824
0
  if (!child->SendInitialize(aRootLayerTreeId)) {
825
0
    return nullptr;
826
0
  }
827
0
828
0
  RefPtr<APZCTreeManagerChild> apz = nullptr;
829
0
  if (aOptions.UseAPZ()) {
830
0
    PAPZCTreeManagerChild* papz = child->SendPAPZCTreeManagerConstructor(LayersId{0});
831
0
    if (!papz) {
832
0
      return nullptr;
833
0
    }
834
0
    apz = static_cast<APZCTreeManagerChild*>(papz);
835
0
836
0
    PAPZInputBridgeChild* pinput = mGPUChild->SendPAPZInputBridgeConstructor(aRootLayerTreeId);
837
0
    if (!pinput) {
838
0
      return nullptr;
839
0
    }
840
0
    apz->SetInputBridge(static_cast<APZInputBridgeChild*>(pinput));
841
0
  }
842
0
843
0
  RefPtr<RemoteCompositorSession> session =
844
0
    new RemoteCompositorSession(aWidget, child, widget, apz, aRootLayerTreeId);
845
0
  return session.forget();
846
#else
847
  gfxCriticalNote << "Platform does not support out-of-process compositing";
848
  return nullptr;
849
#endif
850
}
851
852
bool
853
GPUProcessManager::CreateContentBridges(base::ProcessId aOtherProcess,
854
                                        ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
855
                                        ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
856
                                        ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
857
                                        ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager,
858
                                        nsTArray<uint32_t>* aNamespaces)
859
0
{
860
0
  if (!CreateContentCompositorManager(aOtherProcess, aOutCompositor) ||
861
0
      !CreateContentImageBridge(aOtherProcess, aOutImageBridge) ||
862
0
      !CreateContentVRManager(aOtherProcess, aOutVRBridge))
863
0
  {
864
0
    return false;
865
0
  }
866
0
  // VideoDeocderManager is only supported in the GPU process, so we allow this to be
867
0
  // fallible.
868
0
  CreateContentVideoDecoderManager(aOtherProcess, aOutVideoManager);
869
0
  // Allocates 3 namespaces(for CompositorManagerChild, CompositorBridgeChild and ImageBridgeChild)
870
0
  aNamespaces->AppendElement(AllocateNamespace());
871
0
  aNamespaces->AppendElement(AllocateNamespace());
872
0
  aNamespaces->AppendElement(AllocateNamespace());
873
0
  return true;
874
0
}
875
876
bool
877
GPUProcessManager::CreateContentCompositorManager(base::ProcessId aOtherProcess,
878
                                                  ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint)
879
0
{
880
0
  ipc::Endpoint<PCompositorManagerParent> parentPipe;
881
0
  ipc::Endpoint<PCompositorManagerChild> childPipe;
882
0
883
0
  base::ProcessId parentPid = EnsureGPUReady()
884
0
                              ? mGPUChild->OtherPid()
885
0
                              : base::GetCurrentProcId();
886
0
887
0
  nsresult rv = PCompositorManager::CreateEndpoints(
888
0
    parentPid,
889
0
    aOtherProcess,
890
0
    &parentPipe,
891
0
    &childPipe);
892
0
  if (NS_FAILED(rv)) {
893
0
    gfxCriticalNote << "Could not create content compositor manager: " << hexa(int(rv));
894
0
    return false;
895
0
  }
896
0
897
0
  if (mGPUChild) {
898
0
    mGPUChild->SendNewContentCompositorManager(std::move(parentPipe));
899
0
  } else {
900
0
    CompositorManagerParent::Create(std::move(parentPipe));
901
0
  }
902
0
903
0
  *aOutEndpoint = std::move(childPipe);
904
0
  return true;
905
0
}
906
907
bool
908
GPUProcessManager::CreateContentImageBridge(base::ProcessId aOtherProcess,
909
                                            ipc::Endpoint<PImageBridgeChild>* aOutEndpoint)
910
0
{
911
0
  EnsureImageBridgeChild();
912
0
913
0
  base::ProcessId parentPid = EnsureGPUReady()
914
0
                              ? mGPUChild->OtherPid()
915
0
                              : base::GetCurrentProcId();
916
0
917
0
  ipc::Endpoint<PImageBridgeParent> parentPipe;
918
0
  ipc::Endpoint<PImageBridgeChild> childPipe;
919
0
  nsresult rv = PImageBridge::CreateEndpoints(
920
0
    parentPid,
921
0
    aOtherProcess,
922
0
    &parentPipe,
923
0
    &childPipe);
924
0
  if (NS_FAILED(rv)) {
925
0
    gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv));
926
0
    return false;
927
0
  }
928
0
929
0
  if (mGPUChild) {
930
0
    mGPUChild->SendNewContentImageBridge(std::move(parentPipe));
931
0
  } else {
932
0
    if (!ImageBridgeParent::CreateForContent(std::move(parentPipe))) {
933
0
      return false;
934
0
    }
935
0
  }
936
0
937
0
  *aOutEndpoint = std::move(childPipe);
938
0
  return true;
939
0
}
940
941
base::ProcessId
942
GPUProcessManager::GPUProcessPid()
943
0
{
944
0
  base::ProcessId gpuPid = mGPUChild
945
0
                           ? mGPUChild->OtherPid()
946
0
                           : -1;
947
0
  return gpuPid;
948
0
}
949
950
bool
951
GPUProcessManager::CreateContentVRManager(base::ProcessId aOtherProcess,
952
                                          ipc::Endpoint<PVRManagerChild>* aOutEndpoint)
953
0
{
954
0
  EnsureVRManager();
955
0
956
0
  base::ProcessId parentPid = EnsureGPUReady()
957
0
                              ? mGPUChild->OtherPid()
958
0
                              : base::GetCurrentProcId();
959
0
960
0
  ipc::Endpoint<PVRManagerParent> parentPipe;
961
0
  ipc::Endpoint<PVRManagerChild> childPipe;
962
0
  nsresult rv = PVRManager::CreateEndpoints(
963
0
    parentPid,
964
0
    aOtherProcess,
965
0
    &parentPipe,
966
0
    &childPipe);
967
0
  if (NS_FAILED(rv)) {
968
0
    gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv));
969
0
    return false;
970
0
  }
971
0
972
0
  if (mGPUChild) {
973
0
    mGPUChild->SendNewContentVRManager(std::move(parentPipe));
974
0
  } else {
975
0
    if (!VRManagerParent::CreateForContent(std::move(parentPipe))) {
976
0
      return false;
977
0
    }
978
0
  }
979
0
980
0
  *aOutEndpoint = std::move(childPipe);
981
0
  return true;
982
0
}
983
984
void
985
GPUProcessManager::CreateContentVideoDecoderManager(base::ProcessId aOtherProcess,
986
                                                    ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndpoint)
987
0
{
988
0
  if (!EnsureGPUReady() ||
989
0
      !StaticPrefs::MediaGpuProcessDecoder() ||
990
0
      !mDecodeVideoOnGpuProcess) {
991
0
    return;
992
0
  }
993
0
994
0
  ipc::Endpoint<dom::PVideoDecoderManagerParent> parentPipe;
995
0
  ipc::Endpoint<dom::PVideoDecoderManagerChild> childPipe;
996
0
997
0
  nsresult rv = dom::PVideoDecoderManager::CreateEndpoints(
998
0
    mGPUChild->OtherPid(),
999
0
    aOtherProcess,
1000
0
    &parentPipe,
1001
0
    &childPipe);
1002
0
  if (NS_FAILED(rv)) {
1003
0
    gfxCriticalNote << "Could not create content video decoder: " << hexa(int(rv));
1004
0
    return;
1005
0
  }
1006
0
1007
0
  mGPUChild->SendNewContentVideoDecoderManager(std::move(parentPipe));
1008
0
1009
0
  *aOutEndpoint = std::move(childPipe);
1010
0
}
1011
1012
void
1013
GPUProcessManager::MapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId)
1014
0
{
1015
0
  LayerTreeOwnerTracker::Get()->Map(aLayersId, aOwningId);
1016
0
1017
0
  if (EnsureGPUReady()) {
1018
0
    mGPUChild->SendAddLayerTreeIdMapping(LayerTreeIdMapping(aLayersId, aOwningId));
1019
0
  }
1020
0
}
1021
1022
void
1023
GPUProcessManager::UnmapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId)
1024
0
{
1025
0
  LayerTreeOwnerTracker::Get()->Unmap(aLayersId, aOwningId);
1026
0
1027
0
  if (EnsureGPUReady()) {
1028
0
    mGPUChild->SendRemoveLayerTreeIdMapping(LayerTreeIdMapping(aLayersId, aOwningId));
1029
0
    return;
1030
0
  }
1031
0
  CompositorBridgeParent::DeallocateLayerTreeId(aLayersId);
1032
0
}
1033
1034
bool
1035
GPUProcessManager::IsLayerTreeIdMapped(LayersId aLayersId, base::ProcessId aRequestingId)
1036
0
{
1037
0
  return LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, aRequestingId);
1038
0
}
1039
1040
LayersId
1041
GPUProcessManager::AllocateLayerTreeId()
1042
0
{
1043
0
  // Allocate tree id by using id namespace.
1044
0
  // By it, tree id does not conflict with external image id and
1045
0
  // async image pipeline id.
1046
0
  MOZ_ASSERT(NS_IsMainThread());
1047
0
  ++mResourceId;
1048
0
  if (mResourceId == UINT32_MAX) {
1049
0
    // Move to next id namespace.
1050
0
    mIdNamespace = AllocateNamespace();
1051
0
    mResourceId = 1;
1052
0
  }
1053
0
1054
0
  uint64_t layerTreeId = mIdNamespace;
1055
0
  layerTreeId = (layerTreeId << 32) | mResourceId;
1056
0
  return LayersId{layerTreeId};
1057
0
}
1058
1059
uint32_t
1060
GPUProcessManager::AllocateNamespace()
1061
0
{
1062
0
  MOZ_ASSERT(NS_IsMainThread());
1063
0
  return ++mNextNamespace;
1064
0
}
1065
1066
bool
1067
GPUProcessManager::AllocateAndConnectLayerTreeId(PCompositorBridgeChild* aCompositorBridge,
1068
                                                 base::ProcessId aOtherPid,
1069
                                                 LayersId* aOutLayersId,
1070
                                                 CompositorOptions* aOutCompositorOptions)
1071
0
{
1072
0
  LayersId layersId = AllocateLayerTreeId();
1073
0
  *aOutLayersId = layersId;
1074
0
1075
0
  if (!mGPUChild || !aCompositorBridge) {
1076
0
    // If we're not remoting to another process, or there is no compositor,
1077
0
    // then we'll send at most one message. In this case we can just keep
1078
0
    // the old behavior of making sure the mapping occurs, and maybe sending
1079
0
    // a creation notification.
1080
0
    MapLayerTreeId(layersId, aOtherPid);
1081
0
    if (!aCompositorBridge) {
1082
0
      return false;
1083
0
    }
1084
0
    return aCompositorBridge->SendNotifyChildCreated(layersId, aOutCompositorOptions);
1085
0
  }
1086
0
1087
0
  // Use the combined message path.
1088
0
  LayerTreeOwnerTracker::Get()->Map(layersId, aOtherPid);
1089
0
  return aCompositorBridge->SendMapAndNotifyChildCreated(layersId, aOtherPid, aOutCompositorOptions);
1090
0
}
1091
1092
void
1093
GPUProcessManager::EnsureVsyncIOThread()
1094
0
{
1095
0
  if (mVsyncIOThread) {
1096
0
    return;
1097
0
  }
1098
0
1099
0
  mVsyncIOThread = new VsyncIOThreadHolder();
1100
0
  MOZ_RELEASE_ASSERT(mVsyncIOThread->Start());
1101
0
}
1102
1103
void
1104
GPUProcessManager::ShutdownVsyncIOThread()
1105
0
{
1106
0
  mVsyncIOThread = nullptr;
1107
0
}
1108
1109
void
1110
GPUProcessManager::RegisterRemoteProcessSession(RemoteCompositorSession* aSession)
1111
0
{
1112
0
  mRemoteSessions.AppendElement(aSession);
1113
0
}
1114
1115
void
1116
GPUProcessManager::UnregisterRemoteProcessSession(RemoteCompositorSession* aSession)
1117
0
{
1118
0
  mRemoteSessions.RemoveElement(aSession);
1119
0
}
1120
1121
void
1122
GPUProcessManager::RegisterInProcessSession(InProcessCompositorSession* aSession)
1123
0
{
1124
0
  mInProcessSessions.AppendElement(aSession);
1125
0
}
1126
1127
void
1128
GPUProcessManager::UnregisterInProcessSession(InProcessCompositorSession* aSession)
1129
0
{
1130
0
  mInProcessSessions.RemoveElement(aSession);
1131
0
}
1132
1133
void
1134
GPUProcessManager::AddListener(GPUProcessListener* aListener)
1135
0
{
1136
0
  mListeners.AppendElement(aListener);
1137
0
}
1138
1139
void
1140
GPUProcessManager::RemoveListener(GPUProcessListener* aListener)
1141
0
{
1142
0
  mListeners.RemoveElement(aListener);
1143
0
}
1144
1145
bool
1146
GPUProcessManager::NotifyGpuObservers(const char* aTopic)
1147
0
{
1148
0
  if (!EnsureGPUReady()) {
1149
0
    return false;
1150
0
  }
1151
0
  nsCString topic(aTopic);
1152
0
  mGPUChild->SendNotifyGpuObservers(topic);
1153
0
  return true;
1154
0
}
1155
1156
class GPUMemoryReporter : public MemoryReportingProcess
1157
{
1158
public:
1159
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GPUMemoryReporter, override)
1160
1161
0
  bool IsAlive() const override {
1162
0
    if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
1163
0
      return !!gpm->GetGPUChild();
1164
0
    }
1165
0
    return false;
1166
0
  }
1167
1168
  bool SendRequestMemoryReport(const uint32_t& aGeneration,
1169
                               const bool& aAnonymize,
1170
                               const bool& aMinimizeMemoryUsage,
1171
                               const dom::MaybeFileDesc& aDMDFile) override
1172
0
  {
1173
0
    GPUChild* child = GetChild();
1174
0
    if (!child) {
1175
0
      return false;
1176
0
    }
1177
0
1178
0
    return child->SendRequestMemoryReport(
1179
0
      aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile);
1180
0
  }
1181
1182
0
  int32_t Pid() const override {
1183
0
    if (GPUChild* child = GetChild()) {
1184
0
      return (int32_t)child->OtherPid();
1185
0
    }
1186
0
    return 0;
1187
0
  }
1188
1189
private:
1190
0
  GPUChild* GetChild() const {
1191
0
    if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
1192
0
      if (GPUChild* child = gpm->GetGPUChild()) {
1193
0
        return child;
1194
0
      }
1195
0
    }
1196
0
    return nullptr;
1197
0
  }
1198
1199
protected:
1200
  ~GPUMemoryReporter() = default;
1201
};
1202
1203
RefPtr<MemoryReportingProcess>
1204
GPUProcessManager::GetProcessMemoryReporter()
1205
0
{
1206
0
  if (!EnsureGPUReady()) {
1207
0
    return nullptr;
1208
0
  }
1209
0
  return new GPUMemoryReporter();
1210
0
}
1211
1212
} // namespace gfx
1213
} // namespace mozilla