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