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"
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"
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)
66 # include "gfxWindowsPlatform.h"
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()
90 mUnstableProcessAttempts(0),
91 mTotalProcessAttempts(0),
93 mAppInForeground(true),
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
) {}
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();
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() {
163 nsContentUtils::UnregisterShutdownObserver(mObserver
);
164 Preferences::RemoveObserver(mObserver
, "");
165 nsCOMPtr
<nsIObserverService
> obsServ
= services::GetObserverService();
167 obsServ
->RemoveObserver(mObserver
, "application-foreground");
168 obsServ
->RemoveObserver(mObserver
, "application-background");
169 obsServ
->RemoveObserver(mObserver
, "screen-information-changed");
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
);
187 MOZ_ASSERT(mQueuedPrefs
.IsEmpty());
188 mGPUChild
->SendPreferenceUpdate(pref
);
189 } else if (IsGPUProcessLaunching()) {
190 mQueuedPrefs
.AppendElement(pref
);
194 void GPUProcessManager::ScreenInformationChanged() {
197 mGPUChild
->SendScreenInformationChanged();
202 void GPUProcessManager::NotifyBatteryInfo(
203 const hal::BatteryInformation
& aBatteryInfo
) {
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()) {
222 return mProcessStable
;
225 bool GPUProcessManager::LaunchGPUProcess() {
230 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown
)) {
234 // Start listening for pref changes so we can
235 // forward them to the process once it is running.
237 mObserver
= new Observer(this);
238 nsContentUtils::RegisterShutdownObserver(mObserver
);
239 Preferences::AddStrongObserver(mObserver
, "");
240 nsCOMPtr
<nsIObserverService
> obsServ
= services::GetObserverService();
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;
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
) {
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");
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
)) {
306 if (!aAllowRestart
) {
307 gfxConfig::SetFailed(Feature::GPU_PROCESS
, FeatureStatus::Failed
, aMessage
);
313 FallbackFromAcceleration(mLastError
.value(), mLastErrorMsg
.ref());
315 mLastErrorMsg
.reset();
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.
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);
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.
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
371 bool inShutdown
= AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown
);
374 // Launch the GPU process if it is enabled but hasn't been (re-)launched
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
403 MOZ_DIAGNOSTIC_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS
));
407 if (mGPUChild
->EnsureGPUReady()) {
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
));
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() &&
447 bool GPUProcessManager::EnsureCompositorManagerChild() {
448 nsresult rv
= EnsureGPUReady();
449 if (NS_WARN_IF(rv
== NS_ERROR_ILLEGAL_DURING_SHUTDOWN
)) {
453 if (CompositorManagerChild::IsInitialized(mProcessToken
)) {
458 CompositorManagerChild::InitSameProcess(AllocateNamespace(), mProcessToken
);
462 ipc::Endpoint
<PCompositorManagerParent
> parentPipe
;
463 ipc::Endpoint
<PCompositorManagerChild
> childPipe
;
464 rv
= PCompositorManager::CreateEndpoints(
465 mGPUChild
->OtherPid(), base::GetCurrentProcId(), &parentPipe
, &childPipe
);
467 DisableGPUProcess("Failed to create PCompositorManager endpoints");
471 uint32_t cmNamespace
= AllocateNamespace();
472 mGPUChild
->SendInitCompositorManager(std::move(parentPipe
), cmNamespace
);
473 CompositorManagerChild::Init(std::move(childPipe
), cmNamespace
,
478 bool GPUProcessManager::EnsureImageBridgeChild() {
479 if (ImageBridgeChild::GetSingleton()) {
483 nsresult rv
= EnsureGPUReady();
484 if (NS_WARN_IF(rv
== NS_ERROR_ILLEGAL_DURING_SHUTDOWN
)) {
489 ImageBridgeChild::InitSameProcess(AllocateNamespace());
493 ipc::Endpoint
<PImageBridgeParent
> parentPipe
;
494 ipc::Endpoint
<PImageBridgeChild
> childPipe
;
495 rv
= PImageBridge::CreateEndpoints(
496 mGPUChild
->OtherPid(), base::GetCurrentProcId(), &parentPipe
, &childPipe
);
498 DisableGPUProcess("Failed to create PImageBridge endpoints");
502 mGPUChild
->SendInitImageBridge(std::move(parentPipe
));
503 ImageBridgeChild::InitWithGPUProcess(std::move(childPipe
),
504 AllocateNamespace());
508 bool GPUProcessManager::EnsureVRManager() {
509 if (VRManagerChild::IsCreated()) {
513 nsresult rv
= EnsureGPUReady();
514 if (NS_WARN_IF(rv
== NS_ERROR_ILLEGAL_DURING_SHUTDOWN
)) {
519 VRManagerChild::InitSameProcess();
523 ipc::Endpoint
<PVRManagerParent
> parentPipe
;
524 ipc::Endpoint
<PVRManagerChild
> childPipe
;
525 rv
= PVRManager::CreateEndpoints(
526 mGPUChild
->OtherPid(), base::GetCurrentProcId(), &parentPipe
, &childPipe
);
528 DisableGPUProcess("Failed to create PVRManager endpoints");
532 mGPUChild
->SendInitVRManager(std::move(parentPipe
));
533 VRManagerChild::InitWithGPUProcess(std::move(childPipe
));
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
)) {
549 result
= UiCompositorControllerChild::CreateForSameProcess(aId
, aWidget
);
551 ipc::Endpoint
<PUiCompositorControllerParent
> parentPipe
;
552 ipc::Endpoint
<PUiCompositorControllerChild
> childPipe
;
553 rv
= PUiCompositorController::CreateEndpoints(mGPUChild
->OtherPid(),
554 base::GetCurrentProcId(),
555 &parentPipe
, &childPipe
);
557 DisableGPUProcess("Failed to create PUiCompositorController endpoints");
561 mGPUChild
->SendInitUiCompositorController(aId
, std::move(parentPipe
));
562 result
= UiCompositorControllerChild::CreateForGPUProcess(
563 mProcessToken
, std::move(childPipe
), aWidget
);
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");
582 mGPUChild
= mProcess
->GetActor();
583 mProcessToken
= mProcess
->GetProcessToken();
585 if (mAppInForeground
) {
586 SetProcessIsForeground();
590 ipc::Endpoint
<PVsyncBridgeParent
> vsyncParent
;
591 ipc::Endpoint
<PVsyncBridgeChild
> vsyncChild
;
592 nsresult rv
= PVsyncBridge::CreateEndpoints(mGPUChild
->OtherPid(),
593 base::GetCurrentProcId(),
594 &vsyncParent
, &vsyncChild
);
596 DisableGPUProcess("Failed to create PVsyncBridge endpoints");
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
;
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
660 gfxPlatform::GetPlatform()->CompositorUpdated();
664 mGPUChild
->SendSimulateDeviceReset();
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",
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
);
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())) {
717 mProcess
->KillProcess();
719 SimulateDeviceReset();
722 mLastError
= Some(aError
);
723 mLastErrorMsg
= Some(aMsg
);
728 mLastErrorMsg
.reset();
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();
748 void GPUProcessManager::DisableWebRender(wr::WebRenderError aError
,
749 const nsCString
& aMsg
) {
750 if (DisableWebRenderConfig(aError
, aMsg
)) {
752 DestroyRemoteCompositorSessions();
754 DestroyInProcessCompositorSessions();
756 NotifyListenersOnCompositeDeviceReset();
760 void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError
) {
761 gfxCriticalNote
<< "Handling webrender error " << (unsigned int)aError
;
763 if (aError
== wr::WebRenderError::VIDEO_OVERLAY
) {
764 gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(false);
765 gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false);
768 if (aError
== wr::WebRenderError::VIDEO_HW_OVERLAY
) {
769 gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(false);
772 if (aError
== wr::WebRenderError::VIDEO_SW_OVERLAY
) {
773 gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false);
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");
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
) {
805 // Detect whether the device is resetting too quickly or too much
806 // indicating that we should give up and use software
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());
826 // Ensure device reset handling before re-creating in process sessions.
827 // Normally nsWindow::OnPaint() already handled it.
828 gfxWindowsPlatform::GetPlatform()->HandleDeviceReset();
830 DestroyInProcessCompositorSessions();
831 NotifyListenersOnCompositeDeviceReset();
834 void GPUProcessManager::OnRemoteProcessDeviceReset(GPUProcessHost
* aHost
) {
835 if (OnDeviceReset(/* aTrackThreshold */ true) &&
836 !DisableWebRenderConfig(wr::WebRenderError::EXCESSIVE_RESETS
,
841 DestroyRemoteCompositorSessions();
842 NotifyListenersOnCompositeDeviceReset();
845 void GPUProcessManager::NotifyListenersOnCompositeDeviceReset() {
846 for (const auto& listener
: mListeners
) {
847 listener
->OnCompositorDeviceReset();
851 void GPUProcessManager::OnBlockingProcessUnexpectedShutdown() {
853 CompositorManagerChild::OnGPUProcessLost(mProcess
->GetProcessToken());
855 DestroyProcess(/* aUnexpectedShutdown */ true);
856 mUnstableProcessAttempts
= 0;
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;
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
)
892 mozilla::glean::gpu_process::crash_fallbacks
.Get("none"_ns
).Add(1);
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
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();
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
) {
985 Unused
<< LaunchGPUProcess();
988 // If the GPU process is disabled we can reinitialize rendering immediately.
989 // This will be handled in OnProcessLaunchComplete() if the GPU process is
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",
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());
1056 if (mProcessToken
!= aProcessToken
) {
1057 // This token is for an older process; we can safely ignore it.
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() {
1070 mVsyncIOThread
= nullptr;
1073 void GPUProcessManager::KillProcess() {
1078 mProcess
->KillProcess();
1081 void GPUProcessManager::CrashProcess() {
1086 mProcess
->CrashProcess();
1089 void GPUProcessManager::DestroyProcess(bool aUnexpectedShutdown
) {
1094 mProcess
->Shutdown(aUnexpectedShutdown
);
1097 mGPUChild
= nullptr;
1098 mQueuedPrefs
.Clear();
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
)) {
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
) {
1136 if (!EnsureProtocolsReady()) {
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();
1152 MOZ_DIAGNOSTIC_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS
));
1158 session
= InProcessCompositorSession::Create(
1159 aWidget
, aLayerManager
, layerTreeId
, aScale
, aOptions
,
1160 aUseExternalSurfaceSize
, aSurfaceSize
, AllocateNamespace(),
1164 #if defined(MOZ_WIDGET_ANDROID)
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)
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
);
1192 gfxCriticalNote
<< "Failed to create CompositorBridgeChild";
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
)) {
1206 if (!widget
->Initialize()) {
1209 if (!child
->SendInitialize(aRootLayerTreeId
)) {
1213 RefPtr
<APZCTreeManagerChild
> apz
= nullptr;
1214 if (aOptions
.UseAPZ()) {
1215 PAPZCTreeManagerChild
* papz
=
1216 child
->SendPAPZCTreeManagerConstructor(LayersId
{0});
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
)) {
1230 mGPUChild
->SendInitAPZInputBridge(aRootLayerTreeId
, std::move(parentPipe
));
1232 RefPtr
<APZInputBridgeChild
> inputBridge
=
1233 APZInputBridgeChild::Create(mProcessToken
, std::move(childPipe
));
1238 apz
->SetInputBridge(inputBridge
);
1241 return new RemoteCompositorSession(aWidget
, child
, widget
, apz
,
1244 gfxCriticalNote
<< "Platform does not support out-of-process compositing";
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
,
1259 !CreateContentImageBridge(aOtherProcess
, aChildId
, aOutImageBridge
) ||
1260 !CreateContentVRManager(aOtherProcess
, aChildId
, aOutVRBridge
)) {
1263 // VideoDeocderManager is only supported in the GPU process, so we allow this
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());
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
)) {
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: "
1297 mGPUChild
->SendNewContentCompositorManager(std::move(parentPipe
), aChildId
,
1299 } else if (!CompositorManagerParent::Create(std::move(parentPipe
), aChildId
,
1301 /* aIsRoot */ false)) {
1305 *aOutEndpoint
= std::move(childPipe
);
1309 bool GPUProcessManager::CreateContentImageBridge(
1310 base::ProcessId aOtherProcess
, dom::ContentParentId aChildId
,
1311 ipc::Endpoint
<PImageBridgeChild
>* aOutEndpoint
) {
1312 if (!EnsureImageBridgeChild()) {
1316 nsresult rv
= EnsureGPUReady();
1317 if (NS_WARN_IF(rv
== NS_ERROR_ILLEGAL_DURING_SHUTDOWN
)) {
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
,
1328 if (NS_FAILED(rv
)) {
1329 gfxCriticalNote
<< "Could not create content compositor bridge: "
1335 mGPUChild
->SendNewContentImageBridge(std::move(parentPipe
), aChildId
);
1337 if (!ImageBridgeParent::CreateForContent(std::move(parentPipe
), aChildId
)) {
1342 *aOutEndpoint
= std::move(childPipe
);
1346 base::ProcessId
GPUProcessManager::GPUProcessPid() {
1347 base::ProcessId gpuPid
=
1348 mGPUChild
? mGPUChild
->OtherPid() : base::kInvalidProcessId
;
1352 bool GPUProcessManager::CreateContentVRManager(
1353 base::ProcessId aOtherProcess
, dom::ContentParentId aChildId
,
1354 ipc::Endpoint
<PVRManagerChild
>* aOutEndpoint
) {
1355 if (NS_WARN_IF(!EnsureVRManager())) {
1359 nsresult rv
= EnsureGPUReady();
1360 if (NS_WARN_IF(rv
== NS_ERROR_ILLEGAL_DURING_SHUTDOWN
)) {
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
,
1371 if (NS_FAILED(rv
)) {
1372 gfxCriticalNote
<< "Could not create content compositor bridge: "
1378 mGPUChild
->SendNewContentVRManager(std::move(parentPipe
), aChildId
);
1380 if (!VRManagerParent::CreateForContent(std::move(parentPipe
), aChildId
)) {
1385 *aOutEndpoint
= std::move(childPipe
);
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
)) {
1397 if (NS_FAILED(rv
) || !StaticPrefs::media_gpu_process_decoder() ||
1398 !mDecodeVideoOnGpuProcess
) {
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: "
1413 mGPUChild
->SendNewContentRemoteDecoderManager(std::move(parentPipe
),
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
)) {
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
)) {
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
)) {
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());
1483 if (mResourceId
== UINT32_MAX
) {
1484 // Move to next id namespace.
1485 mIdNamespace
= AllocateNamespace();
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
) {
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
) {
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())) {
1567 nsCString
topic(aTopic
);
1568 mGPUChild
->SendNotifyGpuObservers(topic
);
1572 class GPUMemoryReporter
: public MemoryReportingProcess
{
1574 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GPUMemoryReporter
, override
)
1576 bool IsAlive() const override
{
1577 if (GPUProcessManager
* gpm
= GPUProcessManager::Get()) {
1578 return !!gpm
->GetGPUChild();
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();
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();
1604 GPUChild
* GetChild() const {
1605 if (GPUProcessManager
* gpm
= GPUProcessManager::Get()) {
1606 if (GPUChild
* child
= gpm
->GetGPUChild()) {
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())) {
1623 return new GPUMemoryReporter();
1626 void GPUProcessManager::SetAppInForeground(bool aInForeground
) {
1627 if (mAppInForeground
== aInForeground
) {
1631 mAppInForeground
= aInForeground
;
1633 SetProcessIsForeground();
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"));
1650 setInformationProcess
=
1651 (decltype(NtSetInformationProcess
)*)GetProcAddress(
1652 module
, "NtSetInformationProcess");
1655 if (MOZ_UNLIKELY(!setInformationProcess
)) {
1659 unsigned pid
= GPUProcessPid();
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
) {
1671 BOOLEAN foreground
= mAppInForeground
;
1672 setInformationProcess(processHandle
, NtProcessInformationForeground
,
1673 (PVOID
)&foreground
, sizeof(foreground
));
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__
);
1688 } // namespace mozilla