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