Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / gfx / ipc / GPUProcessManager.cpp
blob97f4d4711164f012afc3fa22597c280cb71b591b
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/. */
7 #include "GPUProcessManager.h"
9 #include "gfxConfig.h"
10 #include "gfxPlatform.h"
11 #include "GPUProcessHost.h"
12 #include "GPUProcessListener.h"
13 #include "mozilla/AppShutdown.h"
14 #include "mozilla/MemoryReportingProcess.h"
15 #include "mozilla/Preferences.h"
16 #include "mozilla/Sprintf.h"
17 #include "mozilla/StaticPtr.h"
18 #include "mozilla/StaticPrefs_gfx.h"
19 #include "mozilla/StaticPrefs_layers.h"
20 #include "mozilla/StaticPrefs_media.h"
21 #include "mozilla/RemoteDecoderManagerChild.h"
22 #include "mozilla/RemoteDecoderManagerParent.h"
23 #include "mozilla/Telemetry.h"
24 #include "mozilla/dom/ContentParent.h"
25 #include "mozilla/gfx/gfxVars.h"
26 #include "mozilla/gfx/GPUChild.h"
27 #include "mozilla/glean/GleanMetrics.h"
28 #include "mozilla/ipc/Endpoint.h"
29 #include "mozilla/ipc/ProcessChild.h"
30 #include "mozilla/layers/APZCTreeManagerChild.h"
31 #include "mozilla/layers/APZInputBridgeChild.h"
32 #include "mozilla/layers/CompositorBridgeChild.h"
33 #include "mozilla/layers/CompositorBridgeParent.h"
34 #include "mozilla/layers/CompositorManagerChild.h"
35 #include "mozilla/layers/CompositorManagerParent.h"
36 #include "mozilla/layers/CompositorOptions.h"
37 #include "mozilla/layers/ImageBridgeChild.h"
38 #include "mozilla/layers/ImageBridgeParent.h"
39 #include "mozilla/layers/InProcessCompositorSession.h"
40 #include "mozilla/layers/LayerTreeOwnerTracker.h"
41 #include "mozilla/layers/RemoteCompositorSession.h"
42 #include "mozilla/webrender/RenderThread.h"
43 #include "mozilla/widget/PlatformWidgetTypes.h"
44 #include "nsAppRunner.h"
45 #include "mozilla/widget/CompositorWidget.h"
46 #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
47 # include "mozilla/widget/CompositorWidgetChild.h"
48 #endif
49 #include "nsBaseWidget.h"
50 #include "nsContentUtils.h"
51 #include "VRManagerChild.h"
52 #include "VRManagerParent.h"
53 #include "VsyncBridgeChild.h"
54 #include "VsyncIOThreadHolder.h"
55 #include "VsyncSource.h"
56 #include "nsExceptionHandler.h"
57 #include "nsPrintfCString.h"
59 #if defined(MOZ_WIDGET_ANDROID)
60 # include "mozilla/java/SurfaceControlManagerWrappers.h"
61 # include "mozilla/widget/AndroidUiThread.h"
62 # include "mozilla/layers/UiCompositorControllerChild.h"
63 #endif // defined(MOZ_WIDGET_ANDROID)
65 #if defined(XP_WIN)
66 # include "gfxWindowsPlatform.h"
67 #endif
69 namespace mozilla {
70 namespace gfx {
72 using namespace mozilla::layers;
74 static StaticAutoPtr<GPUProcessManager> sSingleton;
76 GPUProcessManager* GPUProcessManager::Get() { return sSingleton; }
78 void GPUProcessManager::Initialize() {
79 MOZ_ASSERT(XRE_IsParentProcess());
80 sSingleton = new GPUProcessManager();
83 void GPUProcessManager::Shutdown() { sSingleton = nullptr; }
85 GPUProcessManager::GPUProcessManager()
86 : mTaskFactory(this),
87 mNextNamespace(0),
88 mIdNamespace(0),
89 mResourceId(0),
90 mUnstableProcessAttempts(0),
91 mTotalProcessAttempts(0),
92 mDeviceResetCount(0),
93 mAppInForeground(true),
94 mProcess(nullptr),
95 mProcessToken(0),
96 mProcessStable(true),
97 mGPUChild(nullptr) {
98 MOZ_COUNT_CTOR(GPUProcessManager);
100 mIdNamespace = AllocateNamespace();
102 mDeviceResetLastTime = TimeStamp::Now();
104 LayerTreeOwnerTracker::Initialize();
105 CompositorBridgeParent::InitializeStatics();
108 GPUProcessManager::~GPUProcessManager() {
109 MOZ_COUNT_DTOR(GPUProcessManager);
111 LayerTreeOwnerTracker::Shutdown();
113 // The GPU process should have already been shut down.
114 MOZ_ASSERT(!mProcess && !mGPUChild);
116 // We should have already removed observers.
117 MOZ_ASSERT(!mObserver);
120 NS_IMPL_ISUPPORTS(GPUProcessManager::Observer, nsIObserver);
122 GPUProcessManager::Observer::Observer(GPUProcessManager* aManager)
123 : mManager(aManager) {}
125 NS_IMETHODIMP
126 GPUProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic,
127 const char16_t* aData) {
128 if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
129 mManager->OnXPCOMShutdown();
130 } else if (!strcmp(aTopic, "nsPref:changed")) {
131 mManager->OnPreferenceChange(aData);
132 } else if (!strcmp(aTopic, "application-foreground")) {
133 mManager->mAppInForeground = true;
134 if (!mManager->mProcess && gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
135 Unused << mManager->LaunchGPUProcess();
137 } else if (!strcmp(aTopic, "application-background")) {
138 mManager->mAppInForeground = false;
139 } else if (!strcmp(aTopic, "screen-information-changed")) {
140 mManager->ScreenInformationChanged();
142 return NS_OK;
145 GPUProcessManager::BatteryObserver::BatteryObserver(GPUProcessManager* aManager)
146 : mManager(aManager) {
147 hal::RegisterBatteryObserver(this);
150 void GPUProcessManager::BatteryObserver::Notify(
151 const hal::BatteryInformation& aBatteryInfo) {
152 mManager->NotifyBatteryInfo(aBatteryInfo);
155 void GPUProcessManager::BatteryObserver::ShutDown() {
156 hal::UnregisterBatteryObserver(this);
159 GPUProcessManager::BatteryObserver::~BatteryObserver() {}
161 void GPUProcessManager::OnXPCOMShutdown() {
162 if (mObserver) {
163 nsContentUtils::UnregisterShutdownObserver(mObserver);
164 Preferences::RemoveObserver(mObserver, "");
165 nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
166 if (obsServ) {
167 obsServ->RemoveObserver(mObserver, "application-foreground");
168 obsServ->RemoveObserver(mObserver, "application-background");
169 obsServ->RemoveObserver(mObserver, "screen-information-changed");
171 mObserver = nullptr;
174 CleanShutdown();
177 void GPUProcessManager::OnPreferenceChange(const char16_t* aData) {
178 // We know prefs are ASCII here.
179 NS_LossyConvertUTF16toASCII strData(aData);
181 mozilla::dom::Pref pref(strData, /* isLocked */ false,
182 /* isSanitized */ false, Nothing(), Nothing());
184 Preferences::GetPreference(&pref, GeckoProcessType_GPU,
185 /* remoteType */ ""_ns);
186 if (!!mGPUChild) {
187 MOZ_ASSERT(mQueuedPrefs.IsEmpty());
188 mGPUChild->SendPreferenceUpdate(pref);
189 } else if (IsGPUProcessLaunching()) {
190 mQueuedPrefs.AppendElement(pref);
194 void GPUProcessManager::ScreenInformationChanged() {
195 #if defined(XP_WIN)
196 if (!!mGPUChild) {
197 mGPUChild->SendScreenInformationChanged();
199 #endif
202 void GPUProcessManager::NotifyBatteryInfo(
203 const hal::BatteryInformation& aBatteryInfo) {
204 if (mGPUChild) {
205 mGPUChild->SendNotifyBatteryInfo(aBatteryInfo);
209 void GPUProcessManager::ResetProcessStable() {
210 mTotalProcessAttempts++;
211 mProcessStable = false;
212 mProcessAttemptLastTime = TimeStamp::Now();
215 bool GPUProcessManager::IsProcessStable(const TimeStamp& aNow) {
216 if (mTotalProcessAttempts > 0) {
217 auto delta = (int32_t)(aNow - mProcessAttemptLastTime).ToMilliseconds();
218 if (delta < StaticPrefs::layers_gpu_process_stable_min_uptime_ms()) {
219 return false;
222 return mProcessStable;
225 bool GPUProcessManager::LaunchGPUProcess() {
226 if (mProcess) {
227 return true;
230 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown)) {
231 return false;
234 // Start listening for pref changes so we can
235 // forward them to the process once it is running.
236 if (!mObserver) {
237 mObserver = new Observer(this);
238 nsContentUtils::RegisterShutdownObserver(mObserver);
239 Preferences::AddStrongObserver(mObserver, "");
240 nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
241 if (obsServ) {
242 obsServ->AddObserver(mObserver, "application-foreground", false);
243 obsServ->AddObserver(mObserver, "application-background", false);
244 obsServ->AddObserver(mObserver, "screen-information-changed", false);
248 // Start the Vsync I/O thread so can use it as soon as the process launches.
249 EnsureVsyncIOThread();
251 // If the previous process didn't live long enough, increment our unstable
252 // attempts counter so that we don't end up in a restart loop. If the process
253 // did live long enough, reset the counter so that we don't disable the
254 // process too eagerly.
255 auto newTime = TimeStamp::Now();
256 if (IsProcessStable(newTime)) {
257 mUnstableProcessAttempts = 0;
258 } else {
259 mUnstableProcessAttempts++;
260 mozilla::glean::gpu_process::unstable_launch_attempts.Set(
261 mUnstableProcessAttempts);
263 mTotalProcessAttempts++;
264 mozilla::glean::gpu_process::total_launch_attempts.Set(mTotalProcessAttempts);
265 mProcessAttemptLastTime = newTime;
266 mProcessStable = false;
268 // If the process is launched whilst we're in the background it may never get
269 // a chance to be declared stable before it is killed again. We don't want
270 // this happening repeatedly to result in the GPU process being disabled, so
271 // we assume that processes launched whilst in the background are stable.
272 if (!mAppInForeground) {
273 gfxCriticalNote
274 << "GPU process is being launched whilst app is in background";
275 mProcessStable = true;
278 std::vector<std::string> extraArgs;
279 ipc::ProcessChild::AddPlatformBuildID(extraArgs);
281 // The subprocess is launched asynchronously, so we wait for a callback to
282 // acquire the IPDL actor.
283 mProcess = new GPUProcessHost(this);
284 if (!mProcess->Launch(extraArgs)) {
285 DisableGPUProcess("Failed to launch GPU process");
288 return true;
291 bool GPUProcessManager::IsGPUProcessLaunching() {
292 MOZ_ASSERT(NS_IsMainThread());
293 return !!mProcess && !mGPUChild;
296 void GPUProcessManager::DisableGPUProcess(const char* aMessage) {
297 MaybeDisableGPUProcess(aMessage, /* aAllowRestart */ false);
300 bool GPUProcessManager::MaybeDisableGPUProcess(const char* aMessage,
301 bool aAllowRestart) {
302 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
303 return true;
306 if (!aAllowRestart) {
307 gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, aMessage);
310 bool wantRestart;
311 if (mLastError) {
312 wantRestart =
313 FallbackFromAcceleration(mLastError.value(), mLastErrorMsg.ref());
314 mLastError.reset();
315 mLastErrorMsg.reset();
316 } else {
317 wantRestart = gfxPlatform::FallbackFromAcceleration(
318 FeatureStatus::Unavailable, aMessage,
319 "FEATURE_FAILURE_GPU_PROCESS_ERROR"_ns);
321 if (aAllowRestart && wantRestart) {
322 // The fallback method can make use of the GPU process.
323 return false;
326 if (aAllowRestart) {
327 gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, aMessage);
330 MOZ_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS));
332 gfxCriticalNote << aMessage;
334 gfxPlatform::DisableGPUProcess();
336 mozilla::glean::gpu_process::feature_status.Set(
337 gfxConfig::GetFeature(Feature::GPU_PROCESS)
338 .GetStatusAndFailureIdString());
340 mozilla::glean::gpu_process::crash_fallbacks.Get("disabled"_ns).Add(1);
342 DestroyProcess();
343 ShutdownVsyncIOThread();
345 // Now the stability state is based upon the in process compositor session.
346 ResetProcessStable();
348 // We may have been in the middle of guaranteeing our various services are
349 // available when one failed. Some callers may fallback to using the same
350 // process equivalent, and we need to make sure those services are setup
351 // correctly. We cannot re-enter DisableGPUProcess from this call because we
352 // know that it is disabled in the config above.
353 DebugOnly<bool> ready = EnsureProtocolsReady();
354 MOZ_ASSERT_IF(!ready,
355 AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown));
357 // If we disable the GPU process during reinitialization after a previous
358 // crash, then we need to tell the content processes again, because they
359 // need to rebind to the UI process.
360 HandleProcessLost();
361 return true;
364 nsresult GPUProcessManager::EnsureGPUReady(
365 bool aRetryAfterFallback /* = true */) {
366 MOZ_ASSERT(NS_IsMainThread());
368 // We only wait to fail with NS_ERROR_ILLEGAL_DURING_SHUTDOWN if we would
369 // cause a state change or if we are in the middle of relaunching the GPU
370 // process.
371 bool inShutdown = AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown);
373 while (true) {
374 // Launch the GPU process if it is enabled but hasn't been (re-)launched
375 // yet.
376 if (!mProcess && gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
377 if (NS_WARN_IF(inShutdown)) {
378 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
381 if (!LaunchGPUProcess()) {
382 return NS_ERROR_FAILURE;
386 if (mProcess && !mProcess->IsConnected()) {
387 if (NS_WARN_IF(inShutdown)) {
388 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
391 if (!mProcess->WaitForLaunch()) {
392 // If this fails, we should have fired OnProcessLaunchComplete and
393 // removed the process.
394 MOZ_ASSERT(!mProcess && !mGPUChild);
395 return NS_ERROR_FAILURE;
399 // The only scenario this should be possible is if we raced with the
400 // initialization, which failed, and has already decided to disable the GPU
401 // process.
402 if (!mGPUChild) {
403 MOZ_DIAGNOSTIC_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS));
404 break;
407 if (mGPUChild->EnsureGPUReady()) {
408 return NS_OK;
411 // If the initialization above fails, we likely have a GPU process teardown
412 // waiting in our message queue (or will soon). If the fallback wants us to
413 // give up on the GPU process, we will exit the loop.
414 if (MaybeDisableGPUProcess("Failed to initialize GPU process",
415 /* aAllowRestart */ true)) {
416 MOZ_DIAGNOSTIC_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS));
417 break;
420 // Otherwise HandleProcessLost will explicitly teardown the process and
421 // prevent any pending events from triggering our fallback logic again, and
422 // we will retry with a different configuration.
423 MOZ_DIAGNOSTIC_ASSERT(gfxConfig::IsEnabled(Feature::GPU_PROCESS));
424 OnBlockingProcessUnexpectedShutdown();
426 // Some callers may need to reconfigure if we fellback.
427 if (!aRetryAfterFallback) {
428 return NS_ERROR_NOT_AVAILABLE;
432 // This is the first time we are trying to use the in-process compositor.
433 if (mTotalProcessAttempts == 0) {
434 if (NS_WARN_IF(inShutdown)) {
435 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
437 ResetProcessStable();
439 return NS_ERROR_FAILURE;
442 bool GPUProcessManager::EnsureProtocolsReady() {
443 return EnsureCompositorManagerChild() && EnsureImageBridgeChild() &&
444 EnsureVRManager();
447 bool GPUProcessManager::EnsureCompositorManagerChild() {
448 nsresult rv = EnsureGPUReady();
449 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
450 return false;
453 if (CompositorManagerChild::IsInitialized(mProcessToken)) {
454 return true;
457 if (NS_FAILED(rv)) {
458 CompositorManagerChild::InitSameProcess(AllocateNamespace(), mProcessToken);
459 return true;
462 ipc::Endpoint<PCompositorManagerParent> parentPipe;
463 ipc::Endpoint<PCompositorManagerChild> childPipe;
464 rv = PCompositorManager::CreateEndpoints(
465 mGPUChild->OtherPid(), base::GetCurrentProcId(), &parentPipe, &childPipe);
466 if (NS_FAILED(rv)) {
467 DisableGPUProcess("Failed to create PCompositorManager endpoints");
468 return true;
471 uint32_t cmNamespace = AllocateNamespace();
472 mGPUChild->SendInitCompositorManager(std::move(parentPipe), cmNamespace);
473 CompositorManagerChild::Init(std::move(childPipe), cmNamespace,
474 mProcessToken);
475 return true;
478 bool GPUProcessManager::EnsureImageBridgeChild() {
479 if (ImageBridgeChild::GetSingleton()) {
480 return true;
483 nsresult rv = EnsureGPUReady();
484 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
485 return false;
488 if (NS_FAILED(rv)) {
489 ImageBridgeChild::InitSameProcess(AllocateNamespace());
490 return true;
493 ipc::Endpoint<PImageBridgeParent> parentPipe;
494 ipc::Endpoint<PImageBridgeChild> childPipe;
495 rv = PImageBridge::CreateEndpoints(
496 mGPUChild->OtherPid(), base::GetCurrentProcId(), &parentPipe, &childPipe);
497 if (NS_FAILED(rv)) {
498 DisableGPUProcess("Failed to create PImageBridge endpoints");
499 return true;
502 mGPUChild->SendInitImageBridge(std::move(parentPipe));
503 ImageBridgeChild::InitWithGPUProcess(std::move(childPipe),
504 AllocateNamespace());
505 return true;
508 bool GPUProcessManager::EnsureVRManager() {
509 if (VRManagerChild::IsCreated()) {
510 return true;
513 nsresult rv = EnsureGPUReady();
514 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
515 return false;
518 if (NS_FAILED(rv)) {
519 VRManagerChild::InitSameProcess();
520 return true;
523 ipc::Endpoint<PVRManagerParent> parentPipe;
524 ipc::Endpoint<PVRManagerChild> childPipe;
525 rv = PVRManager::CreateEndpoints(
526 mGPUChild->OtherPid(), base::GetCurrentProcId(), &parentPipe, &childPipe);
527 if (NS_FAILED(rv)) {
528 DisableGPUProcess("Failed to create PVRManager endpoints");
529 return true;
532 mGPUChild->SendInitVRManager(std::move(parentPipe));
533 VRManagerChild::InitWithGPUProcess(std::move(childPipe));
534 return true;
537 #if defined(MOZ_WIDGET_ANDROID)
538 already_AddRefed<UiCompositorControllerChild>
539 GPUProcessManager::CreateUiCompositorController(nsBaseWidget* aWidget,
540 const LayersId aId) {
541 RefPtr<UiCompositorControllerChild> result;
543 nsresult rv = EnsureGPUReady();
544 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
545 return nullptr;
548 if (NS_FAILED(rv)) {
549 result = UiCompositorControllerChild::CreateForSameProcess(aId, aWidget);
550 } else {
551 ipc::Endpoint<PUiCompositorControllerParent> parentPipe;
552 ipc::Endpoint<PUiCompositorControllerChild> childPipe;
553 rv = PUiCompositorController::CreateEndpoints(mGPUChild->OtherPid(),
554 base::GetCurrentProcId(),
555 &parentPipe, &childPipe);
556 if (NS_FAILED(rv)) {
557 DisableGPUProcess("Failed to create PUiCompositorController endpoints");
558 return nullptr;
561 mGPUChild->SendInitUiCompositorController(aId, std::move(parentPipe));
562 result = UiCompositorControllerChild::CreateForGPUProcess(
563 mProcessToken, std::move(childPipe), aWidget);
565 if (result) {
566 result->SetCompositorSurfaceManager(
567 mProcess->GetCompositorSurfaceManager());
570 return result.forget();
572 #endif // defined(MOZ_WIDGET_ANDROID)
574 void GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) {
575 MOZ_ASSERT(mProcess && mProcess == aHost);
577 if (!mProcess->IsConnected()) {
578 DisableGPUProcess("Failed to connect GPU process");
579 return;
582 mGPUChild = mProcess->GetActor();
583 mProcessToken = mProcess->GetProcessToken();
584 #if defined(XP_WIN)
585 if (mAppInForeground) {
586 SetProcessIsForeground();
588 #endif
590 ipc::Endpoint<PVsyncBridgeParent> vsyncParent;
591 ipc::Endpoint<PVsyncBridgeChild> vsyncChild;
592 nsresult rv = PVsyncBridge::CreateEndpoints(mGPUChild->OtherPid(),
593 base::GetCurrentProcId(),
594 &vsyncParent, &vsyncChild);
595 if (NS_FAILED(rv)) {
596 DisableGPUProcess("Failed to create PVsyncBridge endpoints");
597 return;
600 mVsyncBridge = VsyncBridgeChild::Create(mVsyncIOThread, mProcessToken,
601 std::move(vsyncChild));
602 mGPUChild->SendInitVsyncBridge(std::move(vsyncParent));
604 MOZ_ASSERT(!mBatteryObserver);
605 mBatteryObserver = new BatteryObserver(this);
607 // Flush any pref updates that happened during launch and weren't
608 // included in the blobs set up in LaunchGPUProcess.
609 for (const mozilla::dom::Pref& pref : mQueuedPrefs) {
610 Unused << NS_WARN_IF(!mGPUChild->SendPreferenceUpdate(pref));
612 mQueuedPrefs.Clear();
614 CrashReporter::RecordAnnotationCString(
615 CrashReporter::Annotation::GPUProcessStatus, "Running");
617 CrashReporter::RecordAnnotationU32(
618 CrashReporter::Annotation::GPUProcessLaunchCount, mTotalProcessAttempts);
620 ReinitializeRendering();
623 void GPUProcessManager::OnProcessDeclaredStable() { mProcessStable = true; }
625 static bool ShouldLimitDeviceResets(uint32_t count, int32_t deltaMilliseconds) {
626 // We decide to limit by comparing the amount of resets that have happened
627 // and time since the last reset to two prefs.
628 int32_t timeLimit = StaticPrefs::gfx_device_reset_threshold_ms_AtStartup();
629 int32_t countLimit = StaticPrefs::gfx_device_reset_limit_AtStartup();
631 bool hasTimeLimit = timeLimit >= 0;
632 bool hasCountLimit = countLimit >= 0;
634 bool triggeredTime = deltaMilliseconds < timeLimit;
635 bool triggeredCount = count > (uint32_t)countLimit;
637 // If we have both prefs set then it needs to trigger both limits,
638 // otherwise we only test the pref that is set or none
639 if (hasTimeLimit && hasCountLimit) {
640 return triggeredTime && triggeredCount;
641 } else if (hasTimeLimit) {
642 return triggeredTime;
643 } else if (hasCountLimit) {
644 return triggeredCount;
647 return false;
650 void GPUProcessManager::ResetCompositors() {
651 // Note: this will recreate devices in addition to recreating compositors.
652 // This isn't optimal, but this is only used on linux where acceleration
653 // isn't enabled by default, and this way we don't need a new code path.
654 SimulateDeviceReset();
657 void GPUProcessManager::SimulateDeviceReset() {
658 // Make sure we rebuild environment and configuration for accelerated
659 // features.
660 gfxPlatform::GetPlatform()->CompositorUpdated();
662 if (mProcess) {
663 if (mGPUChild) {
664 mGPUChild->SendSimulateDeviceReset();
666 } else {
667 wr::RenderThread::Get()->SimulateDeviceReset();
671 bool GPUProcessManager::FallbackFromAcceleration(wr::WebRenderError aError,
672 const nsCString& aMsg) {
673 if (aError == wr::WebRenderError::INITIALIZE) {
674 return gfxPlatform::FallbackFromAcceleration(
675 gfx::FeatureStatus::Unavailable, "WebRender initialization failed",
676 aMsg);
677 } else if (aError == wr::WebRenderError::MAKE_CURRENT) {
678 return gfxPlatform::FallbackFromAcceleration(
679 gfx::FeatureStatus::Unavailable,
680 "Failed to make render context current",
681 "FEATURE_FAILURE_WEBRENDER_MAKE_CURRENT"_ns);
682 } else if (aError == wr::WebRenderError::RENDER) {
683 return gfxPlatform::FallbackFromAcceleration(
684 gfx::FeatureStatus::Unavailable, "Failed to render WebRender",
685 "FEATURE_FAILURE_WEBRENDER_RENDER"_ns);
686 } else if (aError == wr::WebRenderError::NEW_SURFACE) {
687 // If we cannot create a new Surface even in the final fallback
688 // configuration then force a crash.
689 return gfxPlatform::FallbackFromAcceleration(
690 gfx::FeatureStatus::Unavailable, "Failed to create new surface",
691 "FEATURE_FAILURE_WEBRENDER_NEW_SURFACE"_ns,
692 /* aCrashAfterFinalFallback */ true);
693 } else if (aError == wr::WebRenderError::BEGIN_DRAW) {
694 return gfxPlatform::FallbackFromAcceleration(
695 gfx::FeatureStatus::Unavailable, "BeginDraw() failed",
696 "FEATURE_FAILURE_WEBRENDER_BEGIN_DRAW"_ns);
697 } else if (aError == wr::WebRenderError::EXCESSIVE_RESETS) {
698 return gfxPlatform::FallbackFromAcceleration(
699 gfx::FeatureStatus::Unavailable, "Device resets exceeded threshold",
700 "FEATURE_FAILURE_WEBRENDER_EXCESSIVE_RESETS"_ns);
701 } else {
702 MOZ_ASSERT_UNREACHABLE("Invalid value");
703 return gfxPlatform::FallbackFromAcceleration(
704 gfx::FeatureStatus::Unavailable, "Unhandled failure reason",
705 "FEATURE_FAILURE_WEBRENDER_UNHANDLED"_ns);
709 bool GPUProcessManager::DisableWebRenderConfig(wr::WebRenderError aError,
710 const nsCString& aMsg) {
711 // If we have a stable compositor process, this may just be due to an OOM or
712 // bad driver state. In that case, we should consider restarting the GPU
713 // process, or simulating a device reset to teardown the compositors to
714 // hopefully alleviate the situation.
715 if (IsProcessStable(TimeStamp::Now())) {
716 if (mProcess) {
717 mProcess->KillProcess();
718 } else {
719 SimulateDeviceReset();
722 mLastError = Some(aError);
723 mLastErrorMsg = Some(aMsg);
724 return false;
727 mLastError.reset();
728 mLastErrorMsg.reset();
730 // Disable WebRender
731 bool wantRestart = FallbackFromAcceleration(aError, aMsg);
732 gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(false);
733 gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false);
735 // If we still have the GPU process, and we fallback to a new configuration
736 // that prefers to have the GPU process, reset the counter. Because we
737 // updated the gfxVars, we want to flag the GPUChild to wait for the update
738 // to be processed before creating new compositor sessions, otherwise we risk
739 // them being out of sync with the content/parent processes.
740 if (wantRestart && mProcess && mGPUChild) {
741 mUnstableProcessAttempts = 1;
742 mGPUChild->MarkWaitForVarUpdate();
745 return true;
748 void GPUProcessManager::DisableWebRender(wr::WebRenderError aError,
749 const nsCString& aMsg) {
750 if (DisableWebRenderConfig(aError, aMsg)) {
751 if (mProcess) {
752 DestroyRemoteCompositorSessions();
753 } else {
754 DestroyInProcessCompositorSessions();
756 NotifyListenersOnCompositeDeviceReset();
760 void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) {
761 gfxCriticalNote << "Handling webrender error " << (unsigned int)aError;
762 #ifdef XP_WIN
763 if (aError == wr::WebRenderError::VIDEO_OVERLAY) {
764 gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(false);
765 gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false);
766 return;
768 if (aError == wr::WebRenderError::VIDEO_HW_OVERLAY) {
769 gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(false);
770 return;
772 if (aError == wr::WebRenderError::VIDEO_SW_OVERLAY) {
773 gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false);
774 return;
776 #else
777 if (aError == wr::WebRenderError::VIDEO_OVERLAY ||
778 aError == wr::WebRenderError::VIDEO_HW_OVERLAY ||
779 aError == wr::WebRenderError::VIDEO_SW_OVERLAY) {
780 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
781 return;
783 #endif
785 DisableWebRender(aError, nsCString());
788 /* static */ void GPUProcessManager::RecordDeviceReset(
789 DeviceResetReason aReason) {
790 if (aReason != DeviceResetReason::FORCED_RESET) {
791 Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(aReason));
794 CrashReporter::RecordAnnotationU32(
795 CrashReporter::Annotation::DeviceResetReason,
796 static_cast<uint32_t>(aReason));
799 bool GPUProcessManager::OnDeviceReset(bool aTrackThreshold) {
800 // Ignore resets for thresholding if requested.
801 if (!aTrackThreshold) {
802 return false;
805 // Detect whether the device is resetting too quickly or too much
806 // indicating that we should give up and use software
807 mDeviceResetCount++;
809 auto newTime = TimeStamp::Now();
810 auto delta = (int32_t)(newTime - mDeviceResetLastTime).ToMilliseconds();
811 mDeviceResetLastTime = newTime;
813 // Returns true if we should disable acceleration due to the reset.
814 return ShouldLimitDeviceResets(mDeviceResetCount, delta);
817 void GPUProcessManager::OnInProcessDeviceReset(bool aTrackThreshold) {
818 if (OnDeviceReset(aTrackThreshold)) {
819 gfxCriticalNoteOnce << "In-process device reset threshold exceeded";
820 #ifdef MOZ_WIDGET_GTK
821 // FIXME(aosmond): Should we disable WebRender on other platforms?
822 DisableWebRenderConfig(wr::WebRenderError::EXCESSIVE_RESETS, nsCString());
823 #endif
825 #ifdef XP_WIN
826 // Ensure device reset handling before re-creating in process sessions.
827 // Normally nsWindow::OnPaint() already handled it.
828 gfxWindowsPlatform::GetPlatform()->HandleDeviceReset();
829 #endif
830 DestroyInProcessCompositorSessions();
831 NotifyListenersOnCompositeDeviceReset();
834 void GPUProcessManager::OnRemoteProcessDeviceReset(GPUProcessHost* aHost) {
835 if (OnDeviceReset(/* aTrackThreshold */ true) &&
836 !DisableWebRenderConfig(wr::WebRenderError::EXCESSIVE_RESETS,
837 nsCString())) {
838 return;
841 DestroyRemoteCompositorSessions();
842 NotifyListenersOnCompositeDeviceReset();
845 void GPUProcessManager::NotifyListenersOnCompositeDeviceReset() {
846 for (const auto& listener : mListeners) {
847 listener->OnCompositorDeviceReset();
851 void GPUProcessManager::OnBlockingProcessUnexpectedShutdown() {
852 if (mProcess) {
853 CompositorManagerChild::OnGPUProcessLost(mProcess->GetProcessToken());
855 DestroyProcess(/* aUnexpectedShutdown */ true);
856 mUnstableProcessAttempts = 0;
857 HandleProcessLost();
860 void GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost) {
861 MOZ_ASSERT(mProcess && mProcess == aHost);
863 if (StaticPrefs::layers_gpu_process_crash_also_crashes_browser()) {
864 MOZ_CRASH("GPU process crashed and pref is set to crash the browser.");
867 CompositorManagerChild::OnGPUProcessLost(aHost->GetProcessToken());
868 DestroyProcess(/* aUnexpectedShutdown */ true);
870 if (mUnstableProcessAttempts >
871 uint32_t(StaticPrefs::layers_gpu_process_max_restarts())) {
872 char disableMessage[64];
873 SprintfLiteral(disableMessage, "GPU process disabled after %d attempts",
874 mTotalProcessAttempts);
875 if (!MaybeDisableGPUProcess(disableMessage, /* aAllowRestart */ true)) {
876 // Fallback wants the GPU process. Reset our counter.
877 MOZ_DIAGNOSTIC_ASSERT(gfxConfig::IsEnabled(Feature::GPU_PROCESS));
878 mUnstableProcessAttempts = 0;
879 HandleProcessLost();
880 } else {
881 MOZ_DIAGNOSTIC_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS));
883 } else if (mUnstableProcessAttempts >
884 uint32_t(StaticPrefs::
885 layers_gpu_process_max_restarts_with_decoder()) &&
886 mDecodeVideoOnGpuProcess) {
887 mDecodeVideoOnGpuProcess = false;
888 mozilla::glean::gpu_process::crash_fallbacks.Get("decoding_disabled"_ns)
889 .Add(1);
890 HandleProcessLost();
891 } else {
892 mozilla::glean::gpu_process::crash_fallbacks.Get("none"_ns).Add(1);
893 HandleProcessLost();
897 void GPUProcessManager::HandleProcessLost() {
898 MOZ_ASSERT(NS_IsMainThread());
900 // The shutdown and restart sequence for the GPU process is as follows:
902 // (1) The GPU process dies. IPDL will enqueue an ActorDestroy message on
903 // each channel owning a bridge to the GPU process, on the thread owning
904 // that channel.
906 // (2) The first channel to process its ActorDestroy message will post a
907 // message to the main thread to call NotifyRemoteActorDestroyed on the
908 // GPUProcessManager, which calls OnProcessUnexpectedShutdown if it has
909 // not handled shutdown for this process yet. OnProcessUnexpectedShutdown
910 // is responsible for tearing down the old process and deciding whether
911 // or not to disable the GPU process. It then calls this function,
912 // HandleProcessLost.
914 // (3) We then notify each widget that its session with the compositor is now
915 // invalid. The widget is responsible for destroying its layer manager
916 // and CompositorBridgeChild. Note that at this stage, not all actors may
917 // have received ActorDestroy yet. CompositorBridgeChild may attempt to
918 // send messages, and if this happens, it will probably report a
919 // MsgDropped error. This is okay.
921 // (4) At this point, the UI process has a clean slate: no layers should
922 // exist for the old compositor. We may make a decision on whether or not
923 // to re-launch the GPU process. Or, on Android if the app is in the
924 // background we may decide to wait until it comes to the foreground
925 // before re-launching.
927 // (5) When we do decide to re-launch, or continue without a GPU process, we
928 // notify each ContentParent of the lost connection. It will request new
929 // endpoints from the GPUProcessManager and forward them to its
930 // ContentChild. The parent-side of these endpoints may come from the
931 // compositor thread of the UI process, or the compositor thread of the
932 // GPU process. However, no actual compositors should exist yet.
934 // (6) Each ContentChild will receive new endpoints. It will destroy its
935 // Compositor/ImageBridgeChild singletons and recreate them, as well
936 // as invalidate all retained layers.
938 // (7) In addition, each ContentChild will ask each of its BrowserChildren
939 // to re-request association with the compositor for the window
940 // owning the tab. The sequence of calls looks like:
941 // (a) [CONTENT] ContentChild::RecvReinitRendering
942 // (b) [CONTENT] BrowserChild::ReinitRendering
943 // (c) [CONTENT] BrowserChild::SendEnsureLayersConnected
944 // (d) [UI] BrowserParent::RecvEnsureLayersConnected
945 // (e) [UI] RemoteLayerTreeOwner::EnsureLayersConnected
946 // (f) [UI] CompositorBridgeChild::SendNotifyChildRecreated
948 // Note that at step (e), RemoteLayerTreeOwner will call
949 // GetWindowRenderer on the nsIWidget owning the tab. This step ensures
950 // that a compositor exists for the window. If we decided to launch a new
951 // GPU Process, at this point we block until the process has launched and
952 // we're able to create a new window compositor. Otherwise, if
953 // compositing is now in-process, this will simply create a new
954 // CompositorBridgeParent in the UI process. If there are multiple tabs
955 // in the same window, additional tabs will simply return the already-
956 // established compositor.
958 // Finally, this step serves one other crucial function: tabs must be
959 // associated with a window compositor or else they can't forward
960 // layer transactions. So this step both ensures that a compositor
961 // exists, and that the tab can forward layers.
963 // (8) Last, if the window had no remote tabs, step (7) will not have
964 // applied, and the window will not have a new compositor just yet. The
965 // next refresh tick and paint will ensure that one exists, again via
966 // nsIWidget::GetWindowRenderer. On Android, we called
967 // nsIWidgetListener::RequestRepaint back in step (3) to ensure this
968 // tick occurs, but on other platforms this is not necessary.
970 DestroyRemoteCompositorSessions();
972 #ifdef MOZ_WIDGET_ANDROID
973 java::SurfaceControlManager::GetInstance()->OnGpuProcessLoss();
974 #endif
976 // Re-launch the process if immediately if the GPU process is still enabled.
977 // Except on Android if the app is in the background, where we want to wait
978 // until the app is in the foreground again.
979 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
980 #ifdef MOZ_WIDGET_ANDROID
981 if (mAppInForeground) {
982 #else
984 #endif
985 Unused << LaunchGPUProcess();
987 } else {
988 // If the GPU process is disabled we can reinitialize rendering immediately.
989 // This will be handled in OnProcessLaunchComplete() if the GPU process is
990 // enabled.
991 ReinitializeRendering();
995 void GPUProcessManager::ReinitializeRendering() {
996 // Notify content. This will ensure that each content process re-establishes
997 // a connection to the compositor thread (whether it's in-process or in a
998 // newly launched GPU process).
999 for (const auto& listener : mListeners) {
1000 listener->OnCompositorUnexpectedShutdown();
1003 // Notify any observers that the compositor has been reinitialized,
1004 // eg the ZoomConstraintsClients for parent process documents.
1005 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1006 if (observerService) {
1007 observerService->NotifyObservers(nullptr, "compositor-reinitialized",
1008 nullptr);
1012 void GPUProcessManager::DestroyRemoteCompositorSessions() {
1013 // Build a list of sessions to notify, since notification might delete
1014 // entries from the list.
1015 nsTArray<RefPtr<RemoteCompositorSession>> sessions;
1016 for (auto& session : mRemoteSessions) {
1017 sessions.AppendElement(session);
1020 // Notify each widget that we have lost the GPU process. This will ensure
1021 // that each widget destroys its layer manager and CompositorBridgeChild.
1022 for (const auto& session : sessions) {
1023 session->NotifySessionLost();
1027 void GPUProcessManager::DestroyInProcessCompositorSessions() {
1028 // Build a list of sessions to notify, since notification might delete
1029 // entries from the list.
1030 nsTArray<RefPtr<InProcessCompositorSession>> sessions;
1031 for (auto& session : mInProcessSessions) {
1032 sessions.AppendElement(session);
1035 // Notify each widget that we have lost the GPU process. This will ensure
1036 // that each widget destroys its layer manager and CompositorBridgeChild.
1037 for (const auto& session : sessions) {
1038 session->NotifySessionLost();
1041 // Ensure our stablility state is reset so that we don't necessarily crash
1042 // right away on some WebRender errors.
1043 CompositorBridgeParent::ResetStable();
1044 ResetProcessStable();
1047 void GPUProcessManager::NotifyRemoteActorDestroyed(
1048 const uint64_t& aProcessToken) {
1049 if (!NS_IsMainThread()) {
1050 RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod(
1051 &GPUProcessManager::NotifyRemoteActorDestroyed, aProcessToken);
1052 NS_DispatchToMainThread(task.forget());
1053 return;
1056 if (mProcessToken != aProcessToken) {
1057 // This token is for an older process; we can safely ignore it.
1058 return;
1061 // One of the bridged top-level actors for the GPU process has been
1062 // prematurely terminated, and we're receiving a notification. This
1063 // can happen if the ActorDestroy for a bridged protocol fires
1064 // before the ActorDestroy for PGPUChild.
1065 OnProcessUnexpectedShutdown(mProcess);
1068 void GPUProcessManager::CleanShutdown() {
1069 DestroyProcess();
1070 mVsyncIOThread = nullptr;
1073 void GPUProcessManager::KillProcess() {
1074 if (!mProcess) {
1075 return;
1078 mProcess->KillProcess();
1081 void GPUProcessManager::CrashProcess() {
1082 if (!mProcess) {
1083 return;
1086 mProcess->CrashProcess();
1089 void GPUProcessManager::DestroyProcess(bool aUnexpectedShutdown) {
1090 if (!mProcess) {
1091 return;
1094 mProcess->Shutdown(aUnexpectedShutdown);
1095 mProcessToken = 0;
1096 mProcess = nullptr;
1097 mGPUChild = nullptr;
1098 mQueuedPrefs.Clear();
1099 if (mVsyncBridge) {
1100 mVsyncBridge->Close();
1101 mVsyncBridge = nullptr;
1103 if (mBatteryObserver) {
1104 mBatteryObserver->ShutDown();
1105 mBatteryObserver = nullptr;
1108 CrashReporter::RecordAnnotationCString(
1109 CrashReporter::Annotation::GPUProcessStatus, "Destroyed");
1112 already_AddRefed<CompositorSession> GPUProcessManager::CreateTopLevelCompositor(
1113 nsBaseWidget* aWidget, WebRenderLayerManager* aLayerManager,
1114 CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
1115 bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize,
1116 uint64_t aInnerWindowId, bool* aRetryOut) {
1117 MOZ_ASSERT(aRetryOut);
1119 LayersId layerTreeId = AllocateLayerTreeId();
1121 RefPtr<CompositorSession> session;
1123 nsresult rv = EnsureGPUReady(/* aRetryAfterFallback */ false);
1124 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
1125 *aRetryOut = false;
1126 return nullptr;
1129 // If we used fallback, then retry creating the compositor sessions because
1130 // our configuration may have changed.
1131 if (rv == NS_ERROR_NOT_AVAILABLE) {
1132 *aRetryOut = true;
1133 return nullptr;
1136 if (!EnsureProtocolsReady()) {
1137 *aRetryOut = false;
1138 return nullptr;
1141 if (NS_SUCCEEDED(rv)) {
1142 session = CreateRemoteSession(aWidget, aLayerManager, layerTreeId, aScale,
1143 aOptions, aUseExternalSurfaceSize,
1144 aSurfaceSize, aInnerWindowId);
1145 if (NS_WARN_IF(!session)) {
1146 if (!MaybeDisableGPUProcess("Failed to create remote compositor",
1147 /* aAllowRestart */ true)) {
1148 // Fallback wants the GPU process. Reset our counter.
1149 MOZ_DIAGNOSTIC_ASSERT(gfxConfig::IsEnabled(Feature::GPU_PROCESS));
1150 OnBlockingProcessUnexpectedShutdown();
1151 } else {
1152 MOZ_DIAGNOSTIC_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS));
1154 *aRetryOut = true;
1155 return nullptr;
1157 } else {
1158 session = InProcessCompositorSession::Create(
1159 aWidget, aLayerManager, layerTreeId, aScale, aOptions,
1160 aUseExternalSurfaceSize, aSurfaceSize, AllocateNamespace(),
1161 aInnerWindowId);
1164 #if defined(MOZ_WIDGET_ANDROID)
1165 if (session) {
1166 // Nothing to do if controller gets a nullptr
1167 RefPtr<UiCompositorControllerChild> controller =
1168 CreateUiCompositorController(aWidget, session->RootLayerTreeId());
1169 MOZ_ASSERT(controller);
1170 session->SetUiCompositorControllerChild(controller);
1172 #endif // defined(MOZ_WIDGET_ANDROID)
1174 *aRetryOut = false;
1175 return session.forget();
1178 RefPtr<CompositorSession> GPUProcessManager::CreateRemoteSession(
1179 nsBaseWidget* aWidget, WebRenderLayerManager* aLayerManager,
1180 const LayersId& aRootLayerTreeId, CSSToLayoutDeviceScale aScale,
1181 const CompositorOptions& aOptions, bool aUseExternalSurfaceSize,
1182 const gfx::IntSize& aSurfaceSize, uint64_t aInnerWindowId) {
1183 #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
1184 widget::CompositorWidgetInitData initData;
1185 aWidget->GetCompositorWidgetInitData(&initData);
1187 RefPtr<CompositorBridgeChild> child =
1188 CompositorManagerChild::CreateWidgetCompositorBridge(
1189 mProcessToken, aLayerManager, AllocateNamespace(), aScale, aOptions,
1190 aUseExternalSurfaceSize, aSurfaceSize, aInnerWindowId);
1191 if (!child) {
1192 gfxCriticalNote << "Failed to create CompositorBridgeChild";
1193 return nullptr;
1196 RefPtr<CompositorVsyncDispatcher> dispatcher =
1197 aWidget->GetCompositorVsyncDispatcher();
1198 RefPtr<widget::CompositorWidgetVsyncObserver> observer =
1199 new widget::CompositorWidgetVsyncObserver(mVsyncBridge, aRootLayerTreeId);
1201 widget::CompositorWidgetChild* widget =
1202 new widget::CompositorWidgetChild(dispatcher, observer, initData);
1203 if (!child->SendPCompositorWidgetConstructor(widget, initData)) {
1204 return nullptr;
1206 if (!widget->Initialize()) {
1207 return nullptr;
1209 if (!child->SendInitialize(aRootLayerTreeId)) {
1210 return nullptr;
1213 RefPtr<APZCTreeManagerChild> apz = nullptr;
1214 if (aOptions.UseAPZ()) {
1215 PAPZCTreeManagerChild* papz =
1216 child->SendPAPZCTreeManagerConstructor(LayersId{0});
1217 if (!papz) {
1218 return nullptr;
1220 apz = static_cast<APZCTreeManagerChild*>(papz);
1222 ipc::Endpoint<PAPZInputBridgeParent> parentPipe;
1223 ipc::Endpoint<PAPZInputBridgeChild> childPipe;
1224 nsresult rv = PAPZInputBridge::CreateEndpoints(mGPUChild->OtherPid(),
1225 base::GetCurrentProcId(),
1226 &parentPipe, &childPipe);
1227 if (NS_FAILED(rv)) {
1228 return nullptr;
1230 mGPUChild->SendInitAPZInputBridge(aRootLayerTreeId, std::move(parentPipe));
1232 RefPtr<APZInputBridgeChild> inputBridge =
1233 APZInputBridgeChild::Create(mProcessToken, std::move(childPipe));
1234 if (!inputBridge) {
1235 return nullptr;
1238 apz->SetInputBridge(inputBridge);
1241 return new RemoteCompositorSession(aWidget, child, widget, apz,
1242 aRootLayerTreeId);
1243 #else
1244 gfxCriticalNote << "Platform does not support out-of-process compositing";
1245 return nullptr;
1246 #endif
1249 bool GPUProcessManager::CreateContentBridges(
1250 base::ProcessId aOtherProcess,
1251 ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
1252 ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
1253 ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
1254 ipc::Endpoint<PRemoteDecoderManagerChild>* aOutVideoManager,
1255 dom::ContentParentId aChildId, nsTArray<uint32_t>* aNamespaces) {
1256 const uint32_t cmNamespace = AllocateNamespace();
1257 if (!CreateContentCompositorManager(aOtherProcess, aChildId, cmNamespace,
1258 aOutCompositor) ||
1259 !CreateContentImageBridge(aOtherProcess, aChildId, aOutImageBridge) ||
1260 !CreateContentVRManager(aOtherProcess, aChildId, aOutVRBridge)) {
1261 return false;
1263 // VideoDeocderManager is only supported in the GPU process, so we allow this
1264 // to be fallible.
1265 CreateContentRemoteDecoderManager(aOtherProcess, aChildId, aOutVideoManager);
1266 // Allocates 3 namespaces(for CompositorManagerChild, CompositorBridgeChild
1267 // and ImageBridgeChild)
1268 aNamespaces->AppendElement(cmNamespace);
1269 aNamespaces->AppendElement(AllocateNamespace());
1270 aNamespaces->AppendElement(AllocateNamespace());
1271 return true;
1274 bool GPUProcessManager::CreateContentCompositorManager(
1275 base::ProcessId aOtherProcess, dom::ContentParentId aChildId,
1276 uint32_t aNamespace, ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint) {
1277 ipc::Endpoint<PCompositorManagerParent> parentPipe;
1278 ipc::Endpoint<PCompositorManagerChild> childPipe;
1280 nsresult rv = EnsureGPUReady();
1281 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
1282 return false;
1285 base::ProcessId parentPid =
1286 NS_SUCCEEDED(rv) ? mGPUChild->OtherPid() : base::GetCurrentProcId();
1288 rv = PCompositorManager::CreateEndpoints(parentPid, aOtherProcess,
1289 &parentPipe, &childPipe);
1290 if (NS_FAILED(rv)) {
1291 gfxCriticalNote << "Could not create content compositor manager: "
1292 << hexa(int(rv));
1293 return false;
1296 if (mGPUChild) {
1297 mGPUChild->SendNewContentCompositorManager(std::move(parentPipe), aChildId,
1298 aNamespace);
1299 } else if (!CompositorManagerParent::Create(std::move(parentPipe), aChildId,
1300 aNamespace,
1301 /* aIsRoot */ false)) {
1302 return false;
1305 *aOutEndpoint = std::move(childPipe);
1306 return true;
1309 bool GPUProcessManager::CreateContentImageBridge(
1310 base::ProcessId aOtherProcess, dom::ContentParentId aChildId,
1311 ipc::Endpoint<PImageBridgeChild>* aOutEndpoint) {
1312 if (!EnsureImageBridgeChild()) {
1313 return false;
1316 nsresult rv = EnsureGPUReady();
1317 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
1318 return false;
1321 base::ProcessId parentPid =
1322 NS_SUCCEEDED(rv) ? mGPUChild->OtherPid() : base::GetCurrentProcId();
1324 ipc::Endpoint<PImageBridgeParent> parentPipe;
1325 ipc::Endpoint<PImageBridgeChild> childPipe;
1326 rv = PImageBridge::CreateEndpoints(parentPid, aOtherProcess, &parentPipe,
1327 &childPipe);
1328 if (NS_FAILED(rv)) {
1329 gfxCriticalNote << "Could not create content compositor bridge: "
1330 << hexa(int(rv));
1331 return false;
1334 if (mGPUChild) {
1335 mGPUChild->SendNewContentImageBridge(std::move(parentPipe), aChildId);
1336 } else {
1337 if (!ImageBridgeParent::CreateForContent(std::move(parentPipe), aChildId)) {
1338 return false;
1342 *aOutEndpoint = std::move(childPipe);
1343 return true;
1346 base::ProcessId GPUProcessManager::GPUProcessPid() {
1347 base::ProcessId gpuPid =
1348 mGPUChild ? mGPUChild->OtherPid() : base::kInvalidProcessId;
1349 return gpuPid;
1352 bool GPUProcessManager::CreateContentVRManager(
1353 base::ProcessId aOtherProcess, dom::ContentParentId aChildId,
1354 ipc::Endpoint<PVRManagerChild>* aOutEndpoint) {
1355 if (NS_WARN_IF(!EnsureVRManager())) {
1356 return false;
1359 nsresult rv = EnsureGPUReady();
1360 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
1361 return false;
1364 base::ProcessId parentPid =
1365 NS_SUCCEEDED(rv) ? mGPUChild->OtherPid() : base::GetCurrentProcId();
1367 ipc::Endpoint<PVRManagerParent> parentPipe;
1368 ipc::Endpoint<PVRManagerChild> childPipe;
1369 rv = PVRManager::CreateEndpoints(parentPid, aOtherProcess, &parentPipe,
1370 &childPipe);
1371 if (NS_FAILED(rv)) {
1372 gfxCriticalNote << "Could not create content compositor bridge: "
1373 << hexa(int(rv));
1374 return false;
1377 if (mGPUChild) {
1378 mGPUChild->SendNewContentVRManager(std::move(parentPipe), aChildId);
1379 } else {
1380 if (!VRManagerParent::CreateForContent(std::move(parentPipe), aChildId)) {
1381 return false;
1385 *aOutEndpoint = std::move(childPipe);
1386 return true;
1389 void GPUProcessManager::CreateContentRemoteDecoderManager(
1390 base::ProcessId aOtherProcess, dom::ContentParentId aChildId,
1391 ipc::Endpoint<PRemoteDecoderManagerChild>* aOutEndpoint) {
1392 nsresult rv = EnsureGPUReady();
1393 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
1394 return;
1397 if (NS_FAILED(rv) || !StaticPrefs::media_gpu_process_decoder() ||
1398 !mDecodeVideoOnGpuProcess) {
1399 return;
1402 ipc::Endpoint<PRemoteDecoderManagerParent> parentPipe;
1403 ipc::Endpoint<PRemoteDecoderManagerChild> childPipe;
1405 rv = PRemoteDecoderManager::CreateEndpoints(
1406 mGPUChild->OtherPid(), aOtherProcess, &parentPipe, &childPipe);
1407 if (NS_FAILED(rv)) {
1408 gfxCriticalNote << "Could not create content video decoder: "
1409 << hexa(int(rv));
1410 return;
1413 mGPUChild->SendNewContentRemoteDecoderManager(std::move(parentPipe),
1414 aChildId);
1416 *aOutEndpoint = std::move(childPipe);
1419 void GPUProcessManager::InitVideoBridge(
1420 ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge,
1421 layers::VideoBridgeSource aSource) {
1422 nsresult rv = EnsureGPUReady();
1423 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
1424 return;
1427 if (NS_SUCCEEDED(rv)) {
1428 mGPUChild->SendInitVideoBridge(std::move(aVideoBridge), aSource);
1432 void GPUProcessManager::MapLayerTreeId(LayersId aLayersId,
1433 base::ProcessId aOwningId) {
1434 nsresult rv = EnsureGPUReady();
1435 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
1436 return;
1439 if (NS_SUCCEEDED(rv)) {
1440 mGPUChild->SendAddLayerTreeIdMapping(
1441 LayerTreeIdMapping(aLayersId, aOwningId));
1444 // Must do this *after* the call to EnsureGPUReady, so that if the
1445 // process is launched as a result then it is initialized without this
1446 // LayersId, meaning it can be successfully mapped.
1447 LayerTreeOwnerTracker::Get()->Map(aLayersId, aOwningId);
1450 void GPUProcessManager::UnmapLayerTreeId(LayersId aLayersId,
1451 base::ProcessId aOwningId) {
1452 // Only call EnsureGPUReady() if we have already launched the process, to
1453 // avoid launching a new process unnecesarily. (eg if we are backgrounded)
1454 nsresult rv = mProcess ? EnsureGPUReady() : NS_ERROR_NOT_AVAILABLE;
1455 if (NS_WARN_IF(rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN)) {
1456 return;
1459 if (NS_SUCCEEDED(rv)) {
1460 mGPUChild->SendRemoveLayerTreeIdMapping(
1461 LayerTreeIdMapping(aLayersId, aOwningId));
1462 } else if (!mProcess) {
1463 CompositorBridgeParent::DeallocateLayerTreeId(aLayersId);
1466 // Must do this *after* the call to EnsureGPUReady, so that if the
1467 // process is launched as a result then it is initialized with this
1468 // LayersId, meaning it can be successfully unmapped.
1469 LayerTreeOwnerTracker::Get()->Unmap(aLayersId, aOwningId);
1472 bool GPUProcessManager::IsLayerTreeIdMapped(LayersId aLayersId,
1473 base::ProcessId aRequestingId) {
1474 return LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, aRequestingId);
1477 LayersId GPUProcessManager::AllocateLayerTreeId() {
1478 // Allocate tree id by using id namespace.
1479 // By it, tree id does not conflict with external image id and
1480 // async image pipeline id.
1481 MOZ_ASSERT(NS_IsMainThread());
1482 ++mResourceId;
1483 if (mResourceId == UINT32_MAX) {
1484 // Move to next id namespace.
1485 mIdNamespace = AllocateNamespace();
1486 mResourceId = 1;
1489 uint64_t layerTreeId = mIdNamespace;
1490 layerTreeId = (layerTreeId << 32) | mResourceId;
1491 return LayersId{layerTreeId};
1494 uint32_t GPUProcessManager::AllocateNamespace() {
1495 MOZ_ASSERT(NS_IsMainThread());
1496 return ++mNextNamespace;
1499 bool GPUProcessManager::AllocateAndConnectLayerTreeId(
1500 PCompositorBridgeChild* aCompositorBridge, base::ProcessId aOtherPid,
1501 LayersId* aOutLayersId, CompositorOptions* aOutCompositorOptions) {
1502 LayersId layersId = AllocateLayerTreeId();
1503 *aOutLayersId = layersId;
1505 if (!mGPUChild || !aCompositorBridge) {
1506 // If we're not remoting to another process, or there is no compositor,
1507 // then we'll send at most one message. In this case we can just keep
1508 // the old behavior of making sure the mapping occurs, and maybe sending
1509 // a creation notification.
1510 MapLayerTreeId(layersId, aOtherPid);
1511 if (!aCompositorBridge) {
1512 return false;
1514 return aCompositorBridge->SendNotifyChildCreated(layersId,
1515 aOutCompositorOptions);
1518 // Use the combined message path.
1519 LayerTreeOwnerTracker::Get()->Map(layersId, aOtherPid);
1520 return aCompositorBridge->SendMapAndNotifyChildCreated(layersId, aOtherPid,
1521 aOutCompositorOptions);
1524 void GPUProcessManager::EnsureVsyncIOThread() {
1525 if (mVsyncIOThread) {
1526 return;
1529 mVsyncIOThread = new VsyncIOThreadHolder();
1530 MOZ_RELEASE_ASSERT(mVsyncIOThread->Start());
1533 void GPUProcessManager::ShutdownVsyncIOThread() { mVsyncIOThread = nullptr; }
1535 void GPUProcessManager::RegisterRemoteProcessSession(
1536 RemoteCompositorSession* aSession) {
1537 mRemoteSessions.AppendElement(aSession);
1540 void GPUProcessManager::UnregisterRemoteProcessSession(
1541 RemoteCompositorSession* aSession) {
1542 mRemoteSessions.RemoveElement(aSession);
1545 void GPUProcessManager::RegisterInProcessSession(
1546 InProcessCompositorSession* aSession) {
1547 mInProcessSessions.AppendElement(aSession);
1550 void GPUProcessManager::UnregisterInProcessSession(
1551 InProcessCompositorSession* aSession) {
1552 mInProcessSessions.RemoveElement(aSession);
1555 void GPUProcessManager::AddListener(GPUProcessListener* aListener) {
1556 mListeners.AppendElement(aListener);
1559 void GPUProcessManager::RemoveListener(GPUProcessListener* aListener) {
1560 mListeners.RemoveElement(aListener);
1563 bool GPUProcessManager::NotifyGpuObservers(const char* aTopic) {
1564 if (NS_FAILED(EnsureGPUReady())) {
1565 return false;
1567 nsCString topic(aTopic);
1568 mGPUChild->SendNotifyGpuObservers(topic);
1569 return true;
1572 class GPUMemoryReporter : public MemoryReportingProcess {
1573 public:
1574 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GPUMemoryReporter, override)
1576 bool IsAlive() const override {
1577 if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
1578 return !!gpm->GetGPUChild();
1580 return false;
1583 bool SendRequestMemoryReport(
1584 const uint32_t& aGeneration, const bool& aAnonymize,
1585 const bool& aMinimizeMemoryUsage,
1586 const Maybe<ipc::FileDescriptor>& aDMDFile) override {
1587 GPUChild* child = GetChild();
1588 if (!child) {
1589 return false;
1592 return child->SendRequestMemoryReport(aGeneration, aAnonymize,
1593 aMinimizeMemoryUsage, aDMDFile);
1596 int32_t Pid() const override {
1597 if (GPUChild* child = GetChild()) {
1598 return (int32_t)child->OtherPid();
1600 return 0;
1603 private:
1604 GPUChild* GetChild() const {
1605 if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
1606 if (GPUChild* child = gpm->GetGPUChild()) {
1607 return child;
1610 return nullptr;
1613 protected:
1614 ~GPUMemoryReporter() = default;
1617 RefPtr<MemoryReportingProcess> GPUProcessManager::GetProcessMemoryReporter() {
1618 // Ensure mProcess is non-null before calling EnsureGPUReady, to avoid
1619 // launching the process if it has not already been launched.
1620 if (!mProcess || NS_FAILED(EnsureGPUReady())) {
1621 return nullptr;
1623 return new GPUMemoryReporter();
1626 void GPUProcessManager::SetAppInForeground(bool aInForeground) {
1627 if (mAppInForeground == aInForeground) {
1628 return;
1631 mAppInForeground = aInForeground;
1632 #if defined(XP_WIN)
1633 SetProcessIsForeground();
1634 #endif
1637 #if defined(XP_WIN)
1638 void GPUProcessManager::SetProcessIsForeground() {
1639 NTSTATUS WINAPI NtSetInformationProcess(
1640 IN HANDLE process_handle, IN ULONG info_class,
1641 IN PVOID process_information, IN ULONG information_length);
1642 constexpr unsigned int NtProcessInformationForeground = 25;
1644 static bool alreadyInitialized = false;
1645 static decltype(NtSetInformationProcess)* setInformationProcess = nullptr;
1646 if (!alreadyInitialized) {
1647 alreadyInitialized = true;
1648 nsModuleHandle module(LoadLibrary(L"ntdll.dll"));
1649 if (module) {
1650 setInformationProcess =
1651 (decltype(NtSetInformationProcess)*)GetProcAddress(
1652 module, "NtSetInformationProcess");
1655 if (MOZ_UNLIKELY(!setInformationProcess)) {
1656 return;
1659 unsigned pid = GPUProcessPid();
1660 if (pid <= 0) {
1661 return;
1663 // Using the handle from mProcess->GetChildProcessHandle() fails;
1664 // the PROCESS_SET_INFORMATION permission is probably missing.
1665 nsAutoHandle processHandle(
1666 ::OpenProcess(PROCESS_SET_INFORMATION, FALSE, pid));
1667 if (!processHandle) {
1668 return;
1671 BOOLEAN foreground = mAppInForeground;
1672 setInformationProcess(processHandle, NtProcessInformationForeground,
1673 (PVOID)&foreground, sizeof(foreground));
1675 #endif
1677 RefPtr<PGPUChild::TestTriggerMetricsPromise>
1678 GPUProcessManager::TestTriggerMetrics() {
1679 if (!NS_WARN_IF(!mGPUChild)) {
1680 return mGPUChild->SendTestTriggerMetrics();
1683 return PGPUChild::TestTriggerMetricsPromise::CreateAndReject(
1684 ipc::ResponseRejectReason::SendError, __func__);
1687 } // namespace gfx
1688 } // namespace mozilla