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