GPUProcessManager.cpp (65969B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "GPUProcessManager.h" 8 9 #include "gfxConfig.h" 10 #include "gfxPlatform.h" 11 #include "GPUProcessHost.h" 12 #include "GPUProcessListener.h" 13 #include "mozilla/AppShutdown.h" 14 #include "mozilla/MemoryReportingProcess.h" 15 #include "mozilla/Preferences.h" 16 #include "mozilla/RDDChild.h" 17 #include "mozilla/RDDProcessManager.h" 18 #include "mozilla/RemoteMediaManagerChild.h" 19 #include "mozilla/RemoteMediaManagerParent.h" 20 #include "mozilla/Sprintf.h" 21 #include "mozilla/StaticPtr.h" 22 #include "mozilla/StaticPrefs_gfx.h" 23 #include "mozilla/StaticPrefs_layers.h" 24 #include "mozilla/StaticPrefs_media.h" 25 #include "mozilla/dom/ContentParent.h" 26 #include "mozilla/gfx/gfxVars.h" 27 #include "mozilla/gfx/GPUChild.h" 28 #include "mozilla/gfx/GPUParent.h" 29 #include "mozilla/glean/GfxMetrics.h" 30 #include "mozilla/ipc/Endpoint.h" 31 #include "mozilla/ipc/ProcessChild.h" 32 #include "mozilla/layers/APZCTreeManagerChild.h" 33 #include "mozilla/layers/APZInputBridgeChild.h" 34 #include "mozilla/layers/CompositorBridgeChild.h" 35 #include "mozilla/layers/CompositorBridgeParent.h" 36 #include "mozilla/layers/CompositorManagerChild.h" 37 #include "mozilla/layers/CompositorManagerParent.h" 38 #include "mozilla/layers/CompositorOptions.h" 39 #include "mozilla/layers/ImageBridgeChild.h" 40 #include "mozilla/layers/ImageBridgeParent.h" 41 #include "mozilla/layers/InProcessCompositorSession.h" 42 #include "mozilla/layers/LayerTreeOwnerTracker.h" 43 #include "mozilla/layers/RemoteCompositorSession.h" 44 #include "mozilla/layers/VideoBridgeParent.h" 45 #include "mozilla/webrender/RenderThread.h" 46 #include "mozilla/widget/PlatformWidgetTypes.h" 47 #include "nsAppRunner.h" 48 #include "mozilla/widget/CompositorWidget.h" 49 #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING 50 # include "mozilla/widget/CompositorWidgetChild.h" 51 #endif 52 #include "nsIWidget.h" 53 #include "nsContentUtils.h" 54 #include "VRManagerChild.h" 55 #include "VRManagerParent.h" 56 #include "VsyncBridgeChild.h" 57 #include "VsyncIOThreadHolder.h" 58 #include "VsyncSource.h" 59 #include "nsExceptionHandler.h" 60 #include "nsPrintfCString.h" 61 62 #ifdef MOZ_WMF_MEDIA_ENGINE 63 # include "mozilla/ipc/UtilityMediaServiceChild.h" 64 #endif 65 66 #if defined(MOZ_WIDGET_ANDROID) 67 # include "mozilla/java/SurfaceControlManagerWrappers.h" 68 # include "mozilla/widget/AndroidUiThread.h" 69 # include "mozilla/layers/UiCompositorControllerChild.h" 70 #endif // defined(MOZ_WIDGET_ANDROID) 71 72 #if defined(XP_WIN) 73 # include "gfxWindowsPlatform.h" 74 # include "mozilla/gfx/DeviceManagerDx.h" 75 #endif 76 77 namespace mozilla { 78 namespace gfx { 79 80 using namespace mozilla::layers; 81 82 static StaticAutoPtr<GPUProcessManager> sSingleton; 83 84 GPUProcessManager* GPUProcessManager::Get() { return sSingleton; } 85 86 void GPUProcessManager::Initialize() { 87 MOZ_ASSERT(XRE_IsParentProcess()); 88 sSingleton = new GPUProcessManager(); 89 } 90 91 void GPUProcessManager::Shutdown() { 92 if (!sSingleton) { 93 return; 94 } 95 sSingleton->ShutdownInternal(); 96 sSingleton = nullptr; 97 } 98 99 GPUProcessManager::GPUProcessManager() 100 : mTaskFactory(this), 101 mNextNamespace(0), 102 mIdNamespace(0), 103 mResourceId(0), 104 mUnstableProcessAttempts(0), 105 mTotalProcessAttempts(0), 106 mDeviceResetCount(0), 107 mAppInForeground(true), 108 mProcess(nullptr), 109 mProcessToken(0), 110 mGPUChild(nullptr) { 111 MOZ_COUNT_CTOR(GPUProcessManager); 112 113 mIdNamespace = AllocateNamespace(); 114 115 mDeviceResetLastTime = TimeStamp::Now(); 116 117 LayerTreeOwnerTracker::Initialize(); 118 CompositorBridgeParent::InitializeStatics(); 119 } 120 121 GPUProcessManager::~GPUProcessManager() { 122 MOZ_COUNT_DTOR(GPUProcessManager); 123 124 LayerTreeOwnerTracker::Shutdown(); 125 126 // The GPU process should have already been shut down. 127 MOZ_ASSERT(!mProcess && !mGPUChild); 128 129 // We should have already removed observers. 130 MOZ_DIAGNOSTIC_ASSERT(!mObserver); 131 MOZ_DIAGNOSTIC_ASSERT(!mBatteryObserver); 132 } 133 134 NS_IMPL_ISUPPORTS(GPUProcessManager::Observer, nsIObserver); 135 136 GPUProcessManager::Observer::Observer() { 137 nsContentUtils::RegisterShutdownObserver(this); 138 Preferences::AddStrongObserver(this, ""); 139 if (nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService()) { 140 obsServ->AddObserver(this, "application-foreground", false); 141 obsServ->AddObserver(this, "application-background", false); 142 obsServ->AddObserver(this, "screen-information-changed", false); 143 obsServ->AddObserver(this, "xpcom-will-shutdown", false); 144 } 145 } 146 147 void GPUProcessManager::Observer::Shutdown() { 148 nsContentUtils::UnregisterShutdownObserver(this); 149 Preferences::RemoveObserver(this, ""); 150 if (nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService()) { 151 obsServ->RemoveObserver(this, "application-foreground"); 152 obsServ->RemoveObserver(this, "application-background"); 153 obsServ->RemoveObserver(this, "screen-information-changed"); 154 obsServ->RemoveObserver(this, "xpcom-will-shutdown"); 155 } 156 } 157 158 NS_IMETHODIMP 159 GPUProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic, 160 const char16_t* aData) { 161 if (auto* gpm = GPUProcessManager::Get()) { 162 gpm->NotifyObserve(aTopic, aData); 163 } 164 return NS_OK; 165 } 166 167 void GPUProcessManager::NotifyObserve(const char* aTopic, 168 const char16_t* aData) { 169 if (!strcmp(aTopic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID)) { 170 StopBatteryObserving(); 171 } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { 172 ShutdownInternal(); 173 } else if (!strcmp(aTopic, "nsPref:changed")) { 174 OnPreferenceChange(aData); 175 } else if (!strcmp(aTopic, "application-foreground")) { 176 SetAppInForeground(true); 177 } else if (!strcmp(aTopic, "application-background")) { 178 SetAppInForeground(false); 179 } else if (!strcmp(aTopic, "screen-information-changed")) { 180 ScreenInformationChanged(); 181 } 182 } 183 184 GPUProcessManager::BatteryObserver::BatteryObserver() { 185 hal::RegisterBatteryObserver(this); 186 } 187 188 void GPUProcessManager::BatteryObserver::Notify( 189 const hal::BatteryInformation& aBatteryInfo) { 190 if (auto* gpm = GPUProcessManager::Get()) { 191 gpm->NotifyBatteryInfo(aBatteryInfo); 192 } 193 } 194 195 void GPUProcessManager::BatteryObserver::Shutdown() { 196 hal::UnregisterBatteryObserver(this); 197 } 198 199 void GPUProcessManager::OnPreferenceChange(const char16_t* aData) { 200 if (!mGPUChild && !IsGPUProcessLaunching()) { 201 return; 202 } 203 204 // We know prefs are ASCII here. 205 NS_LossyConvertUTF16toASCII strData(aData); 206 207 mozilla::dom::Pref pref(strData, /* isLocked */ false, 208 /* isSanitized */ false, Nothing(), Nothing()); 209 210 Preferences::GetPreference(&pref, GeckoProcessType_GPU, 211 /* remoteType */ ""_ns); 212 if (mGPUChild) { 213 MOZ_ASSERT(mQueuedPrefs.IsEmpty()); 214 mGPUChild->SendPreferenceUpdate(pref); 215 } else { 216 mQueuedPrefs.AppendElement(pref); 217 } 218 } 219 220 void GPUProcessManager::ScreenInformationChanged() { 221 #if defined(XP_WIN) 222 if (!!mGPUChild) { 223 mGPUChild->SendScreenInformationChanged(); 224 } 225 #endif 226 } 227 228 void GPUProcessManager::NotifyBatteryInfo( 229 const hal::BatteryInformation& aBatteryInfo) { 230 if (mGPUChild) { 231 mGPUChild->SendNotifyBatteryInfo(aBatteryInfo); 232 } 233 } 234 235 void GPUProcessManager::MaybeCrashIfGpuProcessOnceStable() { 236 if (StaticPrefs::layers_gpu_process_allow_fallback_to_parent_AtStartup()) { 237 return; 238 } 239 MOZ_RELEASE_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS)); 240 MOZ_RELEASE_ASSERT(!mProcessStableOnce, 241 "Fallback to parent process not allowed!"); 242 } 243 244 void GPUProcessManager::ResetProcessStable() { 245 mTotalProcessAttempts++; 246 mProcessStable = false; 247 mProcessAttemptLastTime = TimeStamp::Now(); 248 } 249 250 bool GPUProcessManager::IsProcessStable(const TimeStamp& aNow) { 251 if (mTotalProcessAttempts > 0) { 252 auto delta = (int32_t)(aNow - mProcessAttemptLastTime).ToMilliseconds(); 253 if (delta < StaticPrefs::layers_gpu_process_stable_min_uptime_ms()) { 254 return false; 255 } 256 } 257 return mProcessStable; 258 } 259 260 nsresult GPUProcessManager::LaunchGPUProcess() { 261 if (mProcess) { 262 return NS_OK; 263 } 264 265 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown)) { 266 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; 267 } 268 269 // Start listening for pref changes so we can 270 // forward them to the process once it is running. 271 if (!mObserver) { 272 mObserver = new Observer(); 273 } 274 275 // Start the Vsync I/O thread so can use it as soon as the process launches. 276 EnsureVsyncIOThread(); 277 278 mTotalProcessAttempts++; 279 mozilla::glean::gpu_process::total_launch_attempts.Set(mTotalProcessAttempts); 280 mProcessAttemptLastTime = TimeStamp::Now(); 281 mProcessStable = false; 282 283 geckoargs::ChildProcessArgs extraArgs; 284 ipc::ProcessChild::AddPlatformBuildID(extraArgs); 285 286 // The subprocess is launched asynchronously, so we wait for a callback to 287 // acquire the IPDL actor. 288 mProcess = new GPUProcessHost(this); 289 if (!mProcess->Launch(std::move(extraArgs))) { 290 DisableGPUProcess("Failed to launch GPU process"); 291 return NS_ERROR_FAILURE; 292 } 293 294 return NS_OK; 295 } 296 297 bool GPUProcessManager::IsGPUProcessLaunching() { 298 MOZ_ASSERT(NS_IsMainThread()); 299 return !!mProcess && !mGPUChild; 300 } 301 302 void GPUProcessManager::DisableGPUProcess(const char* aMessage) { 303 MaybeDisableGPUProcess(aMessage, /* aAllowRestart */ false); 304 } 305 306 bool GPUProcessManager::MaybeDisableGPUProcess(const char* aMessage, 307 bool aAllowRestart) { 308 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { 309 return true; 310 } 311 312 bool wantRestart; 313 { 314 // Collect the gfxVar updates into a single message. 315 gfxVarsCollectUpdates collect; 316 317 if (!aAllowRestart) { 318 gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, 319 aMessage); 320 gfxVars::SetGPUProcessEnabled(false); 321 } 322 323 if (mLastError) { 324 wantRestart = 325 FallbackFromAcceleration(mLastError.value(), mLastErrorMsg.ref()); 326 mLastError.reset(); 327 mLastErrorMsg.reset(); 328 } else { 329 wantRestart = gfxPlatform::FallbackFromAcceleration( 330 FeatureStatus::Unavailable, aMessage, 331 "FEATURE_FAILURE_GPU_PROCESS_ERROR"_ns); 332 } 333 if (aAllowRestart && wantRestart) { 334 // The fallback method can make use of the GPU process. 335 return false; 336 } 337 338 if (aAllowRestart) { 339 gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, 340 aMessage); 341 gfxVars::SetGPUProcessEnabled(false); 342 } 343 344 MOZ_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS)); 345 346 gfxCriticalNote << aMessage; 347 348 gfxPlatform::DisableGPUProcess(); 349 350 MaybeCrashIfGpuProcessOnceStable(); 351 } 352 353 mozilla::glean::gpu_process::feature_status.Set( 354 gfxConfig::GetFeature(Feature::GPU_PROCESS) 355 .GetStatusAndFailureIdString()); 356 357 mozilla::glean::gpu_process::crash_fallbacks.Get("disabled"_ns).Add(1); 358 359 DestroyProcess(); 360 ShutdownVsyncIOThread(); 361 362 // Now the stability state is based upon the in process compositor session. 363 ResetProcessStable(); 364 365 // We may have been in the middle of guaranteeing our various services are 366 // available when one failed. Some callers may fallback to using the same 367 // process equivalent, and we need to make sure those services are setup 368 // correctly. We cannot re-enter DisableGPUProcess from this call because we 369 // know that it is disabled in the config above. 370 if (NS_WARN_IF(NS_FAILED(EnsureGPUReady()))) { 371 MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown)); 372 } else { 373 DebugOnly<bool> ready = EnsureProtocolsReady(); 374 MOZ_ASSERT(ready); 375 } 376 377 // If we disable the GPU process during reinitialization after a previous 378 // crash, then we need to tell the content processes again, because they 379 // need to rebind to the UI process. 380 HandleProcessLost(); 381 return true; 382 } 383 384 bool GPUProcessManager::IsGPUReady() const { 385 // If we have disabled the GPU process, then we know we are always ready. 386 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { 387 MOZ_ASSERT(!mProcess); 388 MOZ_ASSERT(!mGPUChild); 389 return true; 390 } 391 392 // If we have a GPUChild, then we know the process has finished launching. 393 if (mGPUChild) { 394 return mGPUChild->IsGPUReady(); 395 } 396 397 return false; 398 } 399 400 nsresult GPUProcessManager::EnsureGPUReady() { 401 MOZ_ASSERT(NS_IsMainThread()); 402 403 // Common case is we already have a GPU process. 404 if (mProcess && mProcess->IsConnected() && mGPUChild) { 405 MOZ_DIAGNOSTIC_ASSERT(mGPUChild->IsGPUReady()); 406 return NS_OK; 407 } 408 409 // Next most common case is that we are compositing in the parent process. 410 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { 411 MOZ_DIAGNOSTIC_ASSERT(!mProcess); 412 MOZ_DIAGNOSTIC_ASSERT(!mGPUChild); 413 return NS_OK; 414 } 415 416 // We aren't ready and in shutdown, we should just abort. 417 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown)) { 418 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; 419 } 420 421 while (true) { 422 // We allow the GPU process to launch if we are: 423 // 1) in the foreground, as the application is being actively used. 424 // 2) if we have no launch failures, because even if we are backgrounded, we 425 // can try once to secure it. This is useful for geckoview-junit tests. 426 // 3) if our pref is set to allow background launches; this is false by 427 // default on Android due to its issues with keeping the GPU process 428 // alive in the background, and true on all other platforms. 429 // 430 // If we are not in a position to try launching and/or waiting for the GPU 431 // process, then we should just abort for now. The higher levels will fail 432 // to create the content process, but all of this should get recreated when 433 // the app comes back into the foreground. 434 if (!mAppInForeground && mLaunchProcessAttempts > 0 && 435 !StaticPrefs::layers_gpu_process_launch_in_background()) { 436 return NS_ERROR_ABORT; 437 } 438 439 // Launch the GPU process if it is enabled but hasn't been (re-)launched 440 // yet, and wait for it to complete the handshake. As part of WaitForLaunch, 441 // we know that OnProcessLaunchComplete has been called. If it succeeds, 442 // we know that mGPUChild has been set and we already waited for it to be 443 // ready. If it fails, then we know that the GPU process must have been 444 // destroyed and/or disabled. 445 nsresult rv = LaunchGPUProcess(); 446 if (NS_SUCCEEDED(rv) && mProcess->WaitForLaunch() && mGPUChild) { 447 MOZ_DIAGNOSTIC_ASSERT(mGPUChild->IsGPUReady()); 448 break; 449 } 450 451 MOZ_RELEASE_ASSERT(rv != NS_ERROR_ILLEGAL_DURING_SHUTDOWN); 452 MOZ_RELEASE_ASSERT(!mProcess); 453 MOZ_RELEASE_ASSERT(!mGPUChild); 454 MOZ_DIAGNOSTIC_ASSERT(mLaunchProcessAttempts > 0); 455 456 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { 457 break; 458 } 459 } 460 461 return NS_OK; 462 } 463 464 bool GPUProcessManager::EnsureProtocolsReady() { 465 return EnsureCompositorManagerChild() && EnsureImageBridgeChild() && 466 EnsureVRManager(); 467 } 468 469 bool GPUProcessManager::EnsureCompositorManagerChild() { 470 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 471 472 if (CompositorManagerChild::IsInitialized(mProcessToken)) { 473 return true; 474 } 475 476 if (!mGPUChild) { 477 CompositorManagerChild::InitSameProcess(AllocateNamespace(), mProcessToken); 478 return true; 479 } 480 481 ipc::Endpoint<PCompositorManagerParent> parentPipe; 482 ipc::Endpoint<PCompositorManagerChild> childPipe; 483 nsresult rv = PCompositorManager::CreateEndpoints( 484 mGPUChild->OtherEndpointProcInfo(), ipc::EndpointProcInfo::Current(), 485 &parentPipe, &childPipe); 486 if (NS_FAILED(rv)) { 487 DisableGPUProcess("Failed to create PCompositorManager endpoints"); 488 return true; 489 } 490 491 uint32_t cmNamespace = AllocateNamespace(); 492 mGPUChild->SendInitCompositorManager(std::move(parentPipe), cmNamespace); 493 CompositorManagerChild::Init(std::move(childPipe), cmNamespace, 494 mProcessToken); 495 return true; 496 } 497 498 bool GPUProcessManager::EnsureImageBridgeChild() { 499 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 500 501 if (ImageBridgeChild::GetSingleton()) { 502 return true; 503 } 504 505 if (!mGPUChild) { 506 ImageBridgeChild::InitSameProcess(AllocateNamespace()); 507 return true; 508 } 509 510 ipc::Endpoint<PImageBridgeParent> parentPipe; 511 ipc::Endpoint<PImageBridgeChild> childPipe; 512 nsresult rv = PImageBridge::CreateEndpoints( 513 mGPUChild->OtherEndpointProcInfo(), ipc::EndpointProcInfo::Current(), 514 &parentPipe, &childPipe); 515 if (NS_FAILED(rv)) { 516 DisableGPUProcess("Failed to create PImageBridge endpoints"); 517 return true; 518 } 519 520 mGPUChild->SendInitImageBridge(std::move(parentPipe)); 521 ImageBridgeChild::InitWithGPUProcess(std::move(childPipe), 522 AllocateNamespace()); 523 return true; 524 } 525 526 bool GPUProcessManager::EnsureVRManager() { 527 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 528 529 if (VRManagerChild::IsCreated()) { 530 return true; 531 } 532 533 if (!mGPUChild) { 534 VRManagerChild::InitSameProcess(); 535 return true; 536 } 537 538 ipc::Endpoint<PVRManagerParent> parentPipe; 539 ipc::Endpoint<PVRManagerChild> childPipe; 540 nsresult rv = PVRManager::CreateEndpoints(mGPUChild->OtherEndpointProcInfo(), 541 ipc::EndpointProcInfo::Current(), 542 &parentPipe, &childPipe); 543 if (NS_FAILED(rv)) { 544 DisableGPUProcess("Failed to create PVRManager endpoints"); 545 return true; 546 } 547 548 mGPUChild->SendInitVRManager(std::move(parentPipe)); 549 VRManagerChild::InitWithGPUProcess(std::move(childPipe)); 550 return true; 551 } 552 553 #if defined(MOZ_WIDGET_ANDROID) 554 RefPtr<UiCompositorControllerChild> 555 GPUProcessManager::CreateUiCompositorController(nsIWidget* aWidget, 556 const LayersId aId) { 557 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 558 559 if (!mGPUChild) { 560 return UiCompositorControllerChild::CreateForSameProcess(aId, aWidget); 561 } 562 563 ipc::Endpoint<PUiCompositorControllerParent> parentPipe; 564 ipc::Endpoint<PUiCompositorControllerChild> childPipe; 565 nsresult rv = PUiCompositorController::CreateEndpoints( 566 mGPUChild->OtherEndpointProcInfo(), ipc::EndpointProcInfo::Current(), 567 &parentPipe, &childPipe); 568 if (NS_FAILED(rv)) { 569 DisableGPUProcess("Failed to create PUiCompositorController endpoints"); 570 return nullptr; 571 } 572 573 mGPUChild->SendInitUiCompositorController(aId, std::move(parentPipe)); 574 RefPtr<UiCompositorControllerChild> result = 575 UiCompositorControllerChild::CreateForGPUProcess( 576 mProcessToken, std::move(childPipe), aWidget); 577 578 if (result) { 579 result->SetCompositorSurfaceManager( 580 mProcess->GetCompositorSurfaceManager()); 581 } 582 return result; 583 } 584 #endif // defined(MOZ_WIDGET_ANDROID) 585 586 void GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) { 587 MOZ_ASSERT(mProcess && mProcess == aHost); 588 589 // By definition, the process failing to launch is an unstable attempt. While 590 // we did not get to the point where we are using the features, we should just 591 // follow the same fallback procedure. 592 auto* gpuChild = mProcess->GetActor(); 593 if (NS_WARN_IF(!mProcess->IsConnected()) || NS_WARN_IF(!gpuChild) || 594 NS_WARN_IF(!gpuChild->EnsureGPUReady())) { 595 ++mLaunchProcessAttempts; 596 if (mLaunchProcessAttempts > 597 uint32_t(StaticPrefs::layers_gpu_process_max_launch_attempts())) { 598 char disableMessage[64]; 599 SprintfLiteral(disableMessage, 600 "Failed to launch GPU process after %d attempts", 601 mLaunchProcessAttempts); 602 DisableGPUProcess(disableMessage); 603 } else { 604 DestroyProcess(/* aUnexpectedShutdown */ true); 605 } 606 return; 607 } 608 609 mLaunchProcessAttempts = 0; 610 mGPUChild = gpuChild; 611 mProcessToken = mProcess->GetProcessToken(); 612 #if defined(XP_WIN) 613 if (mAppInForeground) { 614 SetProcessIsForeground(); 615 } 616 #endif 617 618 // Set a high priority for the newly-created gpu process. 619 int pID = mProcess->GetChildProcessId(); 620 hal::SetProcessPriority(pID, hal::PROCESS_PRIORITY_FOREGROUND_HIGH); 621 622 ipc::Endpoint<PVsyncBridgeParent> vsyncParent; 623 ipc::Endpoint<PVsyncBridgeChild> vsyncChild; 624 nsresult rv = PVsyncBridge::CreateEndpoints( 625 mGPUChild->OtherEndpointProcInfo(), ipc::EndpointProcInfo::Current(), 626 &vsyncParent, &vsyncChild); 627 if (NS_FAILED(rv)) { 628 DisableGPUProcess("Failed to create PVsyncBridge endpoints"); 629 return; 630 } 631 632 mVsyncBridge = VsyncBridgeChild::Create(mVsyncIOThread, mProcessToken, 633 std::move(vsyncChild)); 634 mGPUChild->SendInitVsyncBridge(std::move(vsyncParent)); 635 636 MOZ_DIAGNOSTIC_ASSERT(!mBatteryObserver); 637 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown)) { 638 mBatteryObserver = new BatteryObserver(); 639 } 640 641 // Flush any pref updates that happened during launch and weren't 642 // included in the blobs set up in LaunchGPUProcess. 643 for (const mozilla::dom::Pref& pref : mQueuedPrefs) { 644 (void)NS_WARN_IF(!mGPUChild->SendPreferenceUpdate(pref)); 645 } 646 mQueuedPrefs.Clear(); 647 648 CrashReporter::RecordAnnotationCString( 649 CrashReporter::Annotation::GPUProcessStatus, "Running"); 650 651 CrashReporter::RecordAnnotationU32( 652 CrashReporter::Annotation::GPUProcessLaunchCount, mTotalProcessAttempts); 653 654 ReinitializeRendering(); 655 } 656 657 void GPUProcessManager::OnProcessDeclaredStable() { mProcessStable = true; } 658 659 static bool ShouldLimitDeviceResets(uint32_t count, int32_t deltaMilliseconds) { 660 // We decide to limit by comparing the amount of resets that have happened 661 // and time since the last reset to two prefs. 662 int32_t timeLimit = StaticPrefs::gfx_device_reset_threshold_ms_AtStartup(); 663 int32_t countLimit = StaticPrefs::gfx_device_reset_limit_AtStartup(); 664 665 bool hasTimeLimit = timeLimit >= 0; 666 bool hasCountLimit = countLimit >= 0; 667 668 bool triggeredTime = deltaMilliseconds < timeLimit; 669 bool triggeredCount = count > (uint32_t)countLimit; 670 671 // If we have both prefs set then it needs to trigger both limits, 672 // otherwise we only test the pref that is set or none 673 if (hasTimeLimit && hasCountLimit) { 674 return triggeredTime && triggeredCount; 675 } else if (hasTimeLimit) { 676 return triggeredTime; 677 } else if (hasCountLimit) { 678 return triggeredCount; 679 } 680 681 return false; 682 } 683 684 void GPUProcessManager::ResetCompositors() { 685 // Note: this will recreate devices in addition to recreating compositors. 686 // This isn't optimal, but this is only used on linux where acceleration 687 // isn't enabled by default, and this way we don't need a new code path. 688 SimulateDeviceReset(); 689 } 690 691 void GPUProcessManager::SimulateDeviceReset() { 692 // Make sure we rebuild environment and configuration for accelerated 693 // features. 694 gfxPlatform::GetPlatform()->CompositorUpdated(); 695 696 if (mProcess) { 697 if (mGPUChild) { 698 mGPUChild->SendSimulateDeviceReset(); 699 } 700 } else { 701 wr::RenderThread::Get()->SimulateDeviceReset(); 702 } 703 } 704 705 bool GPUProcessManager::FallbackFromAcceleration(wr::WebRenderError aError, 706 const nsCString& aMsg) { 707 if (aError == wr::WebRenderError::INITIALIZE) { 708 return gfxPlatform::FallbackFromAcceleration( 709 gfx::FeatureStatus::Unavailable, "WebRender initialization failed", 710 aMsg); 711 } else if (aError == wr::WebRenderError::MAKE_CURRENT) { 712 return gfxPlatform::FallbackFromAcceleration( 713 gfx::FeatureStatus::Unavailable, 714 "Failed to make render context current", 715 "FEATURE_FAILURE_WEBRENDER_MAKE_CURRENT"_ns); 716 } else if (aError == wr::WebRenderError::RENDER) { 717 return gfxPlatform::FallbackFromAcceleration( 718 gfx::FeatureStatus::Unavailable, "Failed to render WebRender", 719 "FEATURE_FAILURE_WEBRENDER_RENDER"_ns); 720 } else if (aError == wr::WebRenderError::NEW_SURFACE) { 721 // If we cannot create a new Surface even in the final fallback 722 // configuration then force a crash. 723 return gfxPlatform::FallbackFromAcceleration( 724 gfx::FeatureStatus::Unavailable, "Failed to create new surface", 725 "FEATURE_FAILURE_WEBRENDER_NEW_SURFACE"_ns, 726 /* aCrashAfterFinalFallback */ true); 727 } else if (aError == wr::WebRenderError::BEGIN_DRAW) { 728 return gfxPlatform::FallbackFromAcceleration( 729 gfx::FeatureStatus::Unavailable, "BeginDraw() failed", 730 "FEATURE_FAILURE_WEBRENDER_BEGIN_DRAW"_ns); 731 } else if (aError == wr::WebRenderError::EXCESSIVE_RESETS) { 732 return gfxPlatform::FallbackFromAcceleration( 733 gfx::FeatureStatus::Unavailable, "Device resets exceeded threshold", 734 "FEATURE_FAILURE_WEBRENDER_EXCESSIVE_RESETS"_ns); 735 } else { 736 MOZ_ASSERT_UNREACHABLE("Invalid value"); 737 return gfxPlatform::FallbackFromAcceleration( 738 gfx::FeatureStatus::Unavailable, "Unhandled failure reason", 739 "FEATURE_FAILURE_WEBRENDER_UNHANDLED"_ns); 740 } 741 } 742 743 void GPUProcessManager::DisableWebRenderConfig(wr::WebRenderError aError, 744 const nsCString& aMsg) { 745 // Clear out any cached errors from a remote device reset. 746 mLastError.reset(); 747 mLastErrorMsg.reset(); 748 749 bool wantRestart; 750 { 751 // Collect the gfxVar updates into a single message. 752 gfxVarsCollectUpdates collect; 753 754 // Disable WebRender 755 wantRestart = FallbackFromAcceleration(aError, aMsg); 756 gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(false); 757 gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false); 758 } 759 760 // If we still have the GPU process, and we fallback to a new configuration 761 // that prefers to have the GPU process, reset the counter. Because we 762 // updated the gfxVars, we call GPUChild::EnsureGPUReady to force us to wait 763 // for the update to be processed before creating new compositor sessions. 764 // Otherwise we risk them being out of sync with the content/parent processes. 765 if (wantRestart && mProcess && mGPUChild) { 766 mUnstableProcessAttempts = 1; 767 mGPUChild->EnsureGPUReady(/* aForceSync */ true); 768 } 769 } 770 771 void GPUProcessManager::DisableWebRender(wr::WebRenderError aError, 772 const nsCString& aMsg) { 773 DisableWebRenderConfig(aError, aMsg); 774 if (mProcess) { 775 DestroyRemoteCompositorSessions(); 776 } else { 777 DestroyInProcessCompositorSessions(); 778 } 779 NotifyListenersOnCompositeDeviceReset(); 780 } 781 782 void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) { 783 gfxCriticalNote << "Handling webrender error " << (unsigned int)aError; 784 #ifdef XP_WIN 785 if (aError == wr::WebRenderError::VIDEO_OVERLAY) { 786 gfxVarsCollectUpdates collect; 787 gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(false); 788 gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false); 789 return; 790 } 791 if (aError == wr::WebRenderError::VIDEO_HW_OVERLAY) { 792 gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(false); 793 return; 794 } 795 if (aError == wr::WebRenderError::VIDEO_SW_OVERLAY) { 796 gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false); 797 return; 798 } 799 if (aError == wr::WebRenderError::DCOMP_TEXTURE_OVERLAY) { 800 gfxVars::SetUseWebRenderDCompositionTextureOverlayWin(false); 801 return; 802 } 803 #else 804 if (aError == wr::WebRenderError::VIDEO_OVERLAY || 805 aError == wr::WebRenderError::VIDEO_HW_OVERLAY || 806 aError == wr::WebRenderError::VIDEO_SW_OVERLAY || 807 aError == wr::WebRenderError::DCOMP_TEXTURE_OVERLAY) { 808 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 809 return; 810 } 811 #endif 812 813 // If we have a stable GPU process, this may just be due to an OOM or bad 814 // driver state. In that case, we should consider restarting the GPU process 815 // to hopefully alleviate the situation. 816 if (mProcess && (IsProcessStable(TimeStamp::Now()) || 817 (kIsAndroid && !mAppInForeground))) { 818 mProcess->KillProcess(/* aGenerateMinidump */ false); 819 mLastError = Some(aError); 820 mLastErrorMsg = Some(""_ns); 821 return; 822 } 823 824 DisableWebRender(aError, ""_ns); 825 } 826 827 /* static */ 828 void GPUProcessManager::RecordDeviceReset(DeviceResetReason aReason) { 829 if (aReason != DeviceResetReason::FORCED_RESET) { 830 glean::gfx::device_reset_reason.AccumulateSingleSample(uint32_t(aReason)); 831 } 832 833 CrashReporter::RecordAnnotationU32( 834 CrashReporter::Annotation::DeviceResetReason, 835 static_cast<uint32_t>(aReason)); 836 } 837 838 /* static */ 839 void GPUProcessManager::NotifyDeviceReset(DeviceResetReason aReason, 840 DeviceResetDetectPlace aPlace) { 841 if (!NS_IsMainThread()) { 842 NS_DispatchToMainThread(NS_NewRunnableFunction( 843 "gfx::GPUProcessManager::NotifyDeviceReset", 844 [aReason, aPlace]() -> void { 845 gfx::GPUProcessManager::NotifyDeviceReset(aReason, aPlace); 846 })); 847 return; 848 } 849 850 #ifdef XP_WIN 851 // Reset and reinitialize the compositor devices 852 if (auto* deviceManager = DeviceManagerDx::Get()) { 853 deviceManager->MaybeResetAndReacquireDevices(); 854 } 855 #else 856 gfx::GPUProcessManager::RecordDeviceReset(aReason); 857 #endif 858 859 if (XRE_IsGPUProcess()) { 860 if (auto* gpuParent = GPUParent::GetSingleton()) { 861 // End up to GPUProcessManager::OnRemoteProcessDeviceReset() 862 gpuParent->NotifyDeviceReset(aReason, aPlace); 863 } else { 864 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 865 } 866 return; 867 } 868 869 MOZ_ASSERT(XRE_IsParentProcess()); 870 if (auto* gpm = GPUProcessManager::Get()) { 871 gpm->OnInProcessDeviceReset(aReason, aPlace); 872 } else { 873 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 874 } 875 } 876 877 bool GPUProcessManager::OnDeviceReset(bool aTrackThreshold) { 878 // Ignore resets for thresholding if requested. 879 if (!aTrackThreshold) { 880 return false; 881 } 882 883 // Detect whether the device is resetting too quickly or too much 884 // indicating that we should give up and use software 885 mDeviceResetCount++; 886 887 auto newTime = TimeStamp::Now(); 888 auto delta = (int32_t)(newTime - mDeviceResetLastTime).ToMilliseconds(); 889 mDeviceResetLastTime = newTime; 890 891 // Returns true if we should disable acceleration due to the reset. 892 return ShouldLimitDeviceResets(mDeviceResetCount, delta); 893 } 894 895 void GPUProcessManager::OnInProcessDeviceReset(DeviceResetReason aReason, 896 DeviceResetDetectPlace aPlace) { 897 gfxCriticalNote << "Detect DeviceReset " << aReason << " " << aPlace 898 << " in Parent process"; 899 900 bool guilty; 901 switch (aReason) { 902 case DeviceResetReason::HUNG: 903 case DeviceResetReason::RESET: 904 case DeviceResetReason::INVALID_CALL: 905 guilty = true; 906 break; 907 default: 908 guilty = false; 909 break; 910 } 911 912 if (OnDeviceReset(guilty)) { 913 gfxCriticalNoteOnce << "In-process device reset threshold exceeded"; 914 #ifdef MOZ_WIDGET_GTK 915 // FIXME(aosmond): Should we disable WebRender on other platforms? 916 DisableWebRenderConfig(wr::WebRenderError::EXCESSIVE_RESETS, nsCString()); 917 #endif 918 } 919 #ifdef XP_WIN 920 // Ensure device reset handling before re-creating in process sessions. 921 // Normally nsWindow::OnPaint() already handled it. 922 gfxWindowsPlatform::GetPlatform()->HandleDeviceReset(); 923 #endif 924 DestroyInProcessCompositorSessions(); 925 NotifyListenersOnCompositeDeviceReset(); 926 } 927 928 void GPUProcessManager::OnRemoteProcessDeviceReset( 929 GPUProcessHost* aHost, const DeviceResetReason& aReason, 930 const DeviceResetDetectPlace& aPlace) { 931 gfxCriticalNote << "Detect DeviceReset " << aReason << " " << aPlace 932 << " in GPU process"; 933 934 if (OnDeviceReset(/* aTrackThreshold */ true)) { 935 // If we have a stable GPU process, this may just be due to an OOM or bad 936 // driver state. In that case, we should consider restarting the GPU process 937 // to hopefully alleviate the situation. 938 if (mProcess && (IsProcessStable(TimeStamp::Now()) || 939 (kIsAndroid && !mAppInForeground))) { 940 mProcess->KillProcess(/* aGenerateMinidump */ false); 941 mLastError = Some(wr::WebRenderError::EXCESSIVE_RESETS); 942 mLastErrorMsg = Some(""_ns); 943 return; 944 } 945 946 DisableWebRenderConfig(wr::WebRenderError::EXCESSIVE_RESETS, ""_ns); 947 } 948 949 DestroyRemoteCompositorSessions(); 950 NotifyListenersOnCompositeDeviceReset(); 951 } 952 953 void GPUProcessManager::NotifyListenersOnCompositeDeviceReset() { 954 nsTArray<RefPtr<GPUProcessListener>> listeners; 955 listeners.AppendElements(mListeners); 956 for (const auto& listener : listeners) { 957 listener->OnCompositorDeviceReset(); 958 } 959 } 960 961 void GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost) { 962 MOZ_ASSERT(mProcess && mProcess == aHost); 963 964 if (StaticPrefs::layers_gpu_process_crash_also_crashes_browser()) { 965 MOZ_CRASH("GPU process crashed and pref is set to crash the browser."); 966 } 967 968 CompositorManagerChild::OnGPUProcessLost(aHost->GetProcessToken()); 969 DestroyProcess(/* aUnexpectedShutdown */ true); 970 971 // If the process didn't live long enough, increment our unstable attempts 972 // counter so that we don't end up in a restart loop. If the process did live 973 // long enough, reset the counter so that we don't disable the process too 974 // eagerly. 975 if (IsProcessStable(TimeStamp::Now())) { 976 mProcessStableOnce = true; 977 mUnstableProcessAttempts = 0; 978 } else if (kIsAndroid && !mAppInForeground) { 979 // On Android if the process is lost whilst in the background it was 980 // probably killed by the OS, and it may never have had a chance to have 981 // been declared stable prior to being killed. We don't want this happening 982 // repeatedly to result in the GPU process being disabled, so treat any 983 // process lost whilst in the background as stable. 984 mUnstableProcessAttempts = 0; 985 } else { 986 mUnstableProcessAttempts++; 987 mozilla::glean::gpu_process::unstable_launch_attempts.Set( 988 mUnstableProcessAttempts); 989 } 990 991 if (mUnstableProcessAttempts > 992 uint32_t(StaticPrefs::layers_gpu_process_max_restarts())) { 993 char disableMessage[64]; 994 SprintfLiteral(disableMessage, "GPU process disabled after %d attempts", 995 mTotalProcessAttempts); 996 if (!MaybeDisableGPUProcess(disableMessage, /* aAllowRestart */ true)) { 997 // Fallback wants the GPU process. Reset our counter. 998 MOZ_DIAGNOSTIC_ASSERT(gfxConfig::IsEnabled(Feature::GPU_PROCESS)); 999 mUnstableProcessAttempts = 0; 1000 HandleProcessLost(); 1001 } else { 1002 MOZ_DIAGNOSTIC_ASSERT(!gfxConfig::IsEnabled(Feature::GPU_PROCESS)); 1003 } 1004 } else if (mUnstableProcessAttempts > 1005 uint32_t(StaticPrefs:: 1006 layers_gpu_process_max_restarts_with_decoder()) && 1007 mDecodeVideoOnGpuProcess) { 1008 mDecodeVideoOnGpuProcess = false; 1009 mozilla::glean::gpu_process::crash_fallbacks.Get("decoding_disabled"_ns) 1010 .Add(1); 1011 HandleProcessLost(); 1012 } else { 1013 mozilla::glean::gpu_process::crash_fallbacks.Get("none"_ns).Add(1); 1014 HandleProcessLost(); 1015 } 1016 } 1017 1018 void GPUProcessManager::HandleProcessLost() { 1019 MOZ_ASSERT(NS_IsMainThread()); 1020 1021 // The shutdown and restart sequence for the GPU process is as follows: 1022 // 1023 // (1) The GPU process dies. IPDL will enqueue an ActorDestroy message on 1024 // each channel owning a bridge to the GPU process, on the thread owning 1025 // that channel. 1026 // 1027 // (2) The first channel to process its ActorDestroy message will post a 1028 // message to the main thread to call NotifyRemoteActorDestroyed on the 1029 // GPUProcessManager, which calls OnProcessUnexpectedShutdown if it has 1030 // not handled shutdown for this process yet. OnProcessUnexpectedShutdown 1031 // is responsible for tearing down the old process and deciding whether 1032 // or not to disable the GPU process. It then calls this function, 1033 // HandleProcessLost. 1034 // 1035 // (3) We then notify each widget that its session with the compositor is now 1036 // invalid. The widget is responsible for destroying its layer manager 1037 // and CompositorBridgeChild. Note that at this stage, not all actors may 1038 // have received ActorDestroy yet. CompositorBridgeChild may attempt to 1039 // send messages, and if this happens, it will probably report a 1040 // MsgDropped error. This is okay. 1041 // 1042 // (4) At this point, the UI process has a clean slate: no layers should 1043 // exist for the old compositor. We may make a decision on whether or not 1044 // to re-launch the GPU process. Or, on Android if the app is in the 1045 // background we may decide to wait until it comes to the foreground 1046 // before re-launching. 1047 // 1048 // (5) When we do decide to re-launch, or continue without a GPU process, we 1049 // notify each ContentParent of the lost connection. It will request new 1050 // endpoints from the GPUProcessManager and forward them to its 1051 // ContentChild. The parent-side of these endpoints may come from the 1052 // compositor thread of the UI process, or the compositor thread of the 1053 // GPU process. However, no actual compositors should exist yet. 1054 // 1055 // (6) Each ContentChild will receive new endpoints. It will destroy its 1056 // Compositor/ImageBridgeChild singletons and recreate them, as well 1057 // as invalidate all retained layers. 1058 // 1059 // (7) In addition, each ContentChild will ask each of its BrowserChildren 1060 // to re-request association with the compositor for the window 1061 // owning the tab. The sequence of calls looks like: 1062 // (a) [CONTENT] ContentChild::RecvReinitRendering 1063 // (b) [CONTENT] BrowserChild::ReinitRendering 1064 // (c) [CONTENT] BrowserChild::SendEnsureLayersConnected 1065 // (d) [UI] BrowserParent::RecvEnsureLayersConnected 1066 // (e) [UI] RemoteLayerTreeOwner::EnsureLayersConnected 1067 // (f) [UI] CompositorBridgeChild::SendNotifyChildRecreated 1068 // 1069 // Note that at step (e), RemoteLayerTreeOwner will call 1070 // GetWindowRenderer on the nsIWidget owning the tab. This step ensures 1071 // that a compositor exists for the window. If we decided to launch a new 1072 // GPU Process, at this point we block until the process has launched and 1073 // we're able to create a new window compositor. Otherwise, if 1074 // compositing is now in-process, this will simply create a new 1075 // CompositorBridgeParent in the UI process. If there are multiple tabs 1076 // in the same window, additional tabs will simply return the already- 1077 // established compositor. 1078 // 1079 // Finally, this step serves one other crucial function: tabs must be 1080 // associated with a window compositor or else they can't forward 1081 // layer transactions. So this step both ensures that a compositor 1082 // exists, and that the tab can forward layers. 1083 // 1084 // (8) Last, if the window had no remote tabs, step (7) will not have 1085 // applied, and the window will not have a new compositor just yet. The 1086 // next refresh tick and paint will ensure that one exists, again via 1087 // nsIWidget::GetWindowRenderer. On Android, we called 1088 // nsIWidgetListener::RequestRepaint back in step (3) to ensure this 1089 // tick occurs, but on other platforms this is not necessary. 1090 1091 DestroyRemoteCompositorSessions(); 1092 1093 #ifdef MOZ_WIDGET_ANDROID 1094 java::SurfaceControlManager::GetInstance()->OnGpuProcessLoss(); 1095 #endif 1096 1097 // Re-launch the process if immediately if the GPU process is still enabled. 1098 // Except on Android if the app is in the background, where we want to wait 1099 // until the app is in the foreground again. 1100 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { 1101 #ifdef MOZ_WIDGET_ANDROID 1102 if (mAppInForeground) { 1103 #else 1104 { 1105 #endif 1106 (void)LaunchGPUProcess(); 1107 } 1108 } else { 1109 // If the GPU process is disabled we can reinitialize rendering immediately. 1110 // This will be handled in OnProcessLaunchComplete() if the GPU process is 1111 // enabled. 1112 ReinitializeRendering(); 1113 } 1114 } 1115 1116 void GPUProcessManager::ReinitializeRendering() { 1117 // Notify content. This will ensure that each content process re-establishes 1118 // a connection to the compositor thread (whether it's in-process or in a 1119 // newly launched GPU process). 1120 nsTArray<RefPtr<GPUProcessListener>> listeners; 1121 listeners.AppendElements(mListeners); 1122 // Make sure any fallback renderers get destroyed first. 1123 for (const auto& listener : listeners) { 1124 listener->OnCompositorDestroyBackgrounded(); 1125 } 1126 // Then do the recreations. 1127 for (const auto& listener : listeners) { 1128 listener->OnCompositorUnexpectedShutdown(); 1129 } 1130 1131 // Notify any observers that the compositor has been reinitialized, 1132 // eg the ZoomConstraintsClients for parent process documents. 1133 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 1134 if (observerService) { 1135 observerService->NotifyObservers(nullptr, "compositor-reinitialized", 1136 nullptr); 1137 } 1138 } 1139 1140 void GPUProcessManager::DestroyRemoteCompositorSessions() { 1141 // Build a list of sessions to notify, since notification might delete 1142 // entries from the list. 1143 nsTArray<RefPtr<RemoteCompositorSession>> sessions; 1144 for (auto& session : mRemoteSessions) { 1145 sessions.AppendElement(session); 1146 } 1147 1148 // Notify each widget that we have lost the GPU process. This will ensure 1149 // that each widget destroys its layer manager and CompositorBridgeChild. 1150 for (const auto& session : sessions) { 1151 session->NotifySessionLost(); 1152 } 1153 } 1154 1155 void GPUProcessManager::DestroyInProcessCompositorSessions() { 1156 // Build a list of sessions to notify, since notification might delete 1157 // entries from the list. 1158 nsTArray<RefPtr<InProcessCompositorSession>> sessions; 1159 for (auto& session : mInProcessSessions) { 1160 sessions.AppendElement(session); 1161 } 1162 1163 // Notify each widget that we have lost the GPU process. This will ensure 1164 // that each widget destroys its layer manager and CompositorBridgeChild. 1165 for (const auto& session : sessions) { 1166 session->NotifySessionLost(); 1167 } 1168 1169 // Ensure our stablility state is reset so that we don't necessarily crash 1170 // right away on some WebRender errors. 1171 CompositorBridgeParent::ResetStable(); 1172 ResetProcessStable(); 1173 } 1174 1175 void GPUProcessManager::NotifyRemoteActorDestroyed( 1176 const uint64_t& aProcessToken) { 1177 if (!NS_IsMainThread()) { 1178 RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod( 1179 &GPUProcessManager::NotifyRemoteActorDestroyed, aProcessToken); 1180 NS_DispatchToMainThread(task.forget()); 1181 return; 1182 } 1183 1184 if (mProcessToken != aProcessToken) { 1185 // This token is for an older process; we can safely ignore it. 1186 return; 1187 } 1188 1189 // One of the bridged top-level actors for the GPU process has been 1190 // prematurely terminated, and we're receiving a notification. This 1191 // can happen if the ActorDestroy for a bridged protocol fires 1192 // before the ActorDestroy for PGPUChild. 1193 OnProcessUnexpectedShutdown(mProcess); 1194 } 1195 1196 void GPUProcessManager::ShutdownInternal() { 1197 if (mObserver) { 1198 mObserver->Shutdown(); 1199 mObserver = nullptr; 1200 } 1201 1202 DestroyProcess(); 1203 mVsyncIOThread = nullptr; 1204 } 1205 1206 void GPUProcessManager::KillProcess(bool aGenerateMinidump) { 1207 if (!NS_IsMainThread()) { 1208 RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod( 1209 &GPUProcessManager::KillProcess, aGenerateMinidump); 1210 NS_DispatchToMainThread(task.forget()); 1211 return; 1212 } 1213 1214 if (!mProcess) { 1215 return; 1216 } 1217 1218 mProcess->KillProcess(aGenerateMinidump); 1219 } 1220 1221 void GPUProcessManager::CrashProcess() { 1222 if (!mProcess) { 1223 return; 1224 } 1225 1226 mProcess->CrashProcess(); 1227 } 1228 1229 void GPUProcessManager::DestroyProcess(bool aUnexpectedShutdown) { 1230 if (!mProcess) { 1231 return; 1232 } 1233 1234 mProcess->Shutdown(aUnexpectedShutdown); 1235 mProcessToken = 0; 1236 mProcess = nullptr; 1237 mGPUChild = nullptr; 1238 mQueuedPrefs.Clear(); 1239 if (mVsyncBridge) { 1240 mVsyncBridge->Close(); 1241 mVsyncBridge = nullptr; 1242 } 1243 StopBatteryObserving(); 1244 1245 CrashReporter::RecordAnnotationCString( 1246 CrashReporter::Annotation::GPUProcessStatus, "Destroyed"); 1247 } 1248 1249 void GPUProcessManager::StopBatteryObserving() { 1250 if (mBatteryObserver) { 1251 mBatteryObserver->Shutdown(); 1252 mBatteryObserver = nullptr; 1253 } 1254 } 1255 1256 already_AddRefed<CompositorSession> GPUProcessManager::CreateTopLevelCompositor( 1257 nsIWidget* aWidget, WebRenderLayerManager* aLayerManager, 1258 CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions, 1259 bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize, 1260 uint64_t aInnerWindowId, bool* aRetryOut) { 1261 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 1262 MOZ_ASSERT(aRetryOut); 1263 1264 if (!EnsureProtocolsReady()) { 1265 *aRetryOut = false; 1266 return nullptr; 1267 } 1268 1269 LayersId layerTreeId = AllocateLayerTreeId(); 1270 RefPtr<CompositorSession> session; 1271 if (mGPUChild) { 1272 session = CreateRemoteSession(aWidget, aLayerManager, layerTreeId, aScale, 1273 aOptions, aUseExternalSurfaceSize, 1274 aSurfaceSize, aInnerWindowId); 1275 if (NS_WARN_IF(!session)) { 1276 // This may have failed for intermittent reasons, or perhaps indicates we 1277 // are fundamentally unable to use acceleration. 1278 // OnProcessUnexpectedShutdown will first attempt to relaunch the GPU 1279 // process in the same configuration a number of times, then fallback from 1280 // acceleration, then finally disable the GPU process if it continues to 1281 // fail. 1282 OnProcessUnexpectedShutdown(mProcess); 1283 *aRetryOut = true; 1284 return nullptr; 1285 } 1286 } else { 1287 session = InProcessCompositorSession::Create( 1288 aWidget, aLayerManager, layerTreeId, aScale, aOptions, 1289 aUseExternalSurfaceSize, aSurfaceSize, AllocateNamespace(), 1290 aInnerWindowId); 1291 } 1292 1293 #if defined(MOZ_WIDGET_ANDROID) 1294 if (session) { 1295 // Nothing to do if controller gets a nullptr 1296 auto controller = 1297 CreateUiCompositorController(aWidget, session->RootLayerTreeId()); 1298 MOZ_ASSERT(controller); 1299 session->SetUiCompositorControllerChild(std::move(controller)); 1300 } 1301 #endif // defined(MOZ_WIDGET_ANDROID) 1302 1303 *aRetryOut = false; 1304 return session.forget(); 1305 } 1306 1307 RefPtr<CompositorSession> GPUProcessManager::CreateRemoteSession( 1308 nsIWidget* aWidget, WebRenderLayerManager* aLayerManager, 1309 const LayersId& aRootLayerTreeId, CSSToLayoutDeviceScale aScale, 1310 const CompositorOptions& aOptions, bool aUseExternalSurfaceSize, 1311 const gfx::IntSize& aSurfaceSize, uint64_t aInnerWindowId) { 1312 #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING 1313 widget::CompositorWidgetInitData initData; 1314 aWidget->GetCompositorWidgetInitData(&initData); 1315 1316 RefPtr<CompositorBridgeChild> child = 1317 CompositorManagerChild::CreateWidgetCompositorBridge( 1318 mProcessToken, aLayerManager, AllocateNamespace(), aScale, aOptions, 1319 aUseExternalSurfaceSize, aSurfaceSize, aInnerWindowId); 1320 if (!child) { 1321 gfxCriticalNote << "Failed to create CompositorBridgeChild"; 1322 return nullptr; 1323 } 1324 1325 RefPtr<CompositorVsyncDispatcher> dispatcher = 1326 aWidget->GetCompositorVsyncDispatcher(); 1327 RefPtr<widget::CompositorWidgetVsyncObserver> observer = 1328 new widget::CompositorWidgetVsyncObserver(mVsyncBridge, aRootLayerTreeId); 1329 1330 widget::CompositorWidgetChild* widget = 1331 new widget::CompositorWidgetChild(dispatcher, observer, initData); 1332 if (!child->SendPCompositorWidgetConstructor(widget, std::move(initData))) { 1333 return nullptr; 1334 } 1335 if (!widget->Initialize(aOptions)) { 1336 return nullptr; 1337 } 1338 if (!child->SendInitialize(aRootLayerTreeId)) { 1339 return nullptr; 1340 } 1341 1342 RefPtr<APZCTreeManagerChild> apz = nullptr; 1343 if (aOptions.UseAPZ()) { 1344 PAPZCTreeManagerChild* papz = 1345 child->SendPAPZCTreeManagerConstructor(LayersId{0}); 1346 if (!papz) { 1347 return nullptr; 1348 } 1349 apz = static_cast<APZCTreeManagerChild*>(papz); 1350 1351 ipc::Endpoint<PAPZInputBridgeParent> parentPipe; 1352 ipc::Endpoint<PAPZInputBridgeChild> childPipe; 1353 nsresult rv = PAPZInputBridge::CreateEndpoints( 1354 mGPUChild->OtherEndpointProcInfo(), ipc::EndpointProcInfo::Current(), 1355 &parentPipe, &childPipe); 1356 if (NS_FAILED(rv)) { 1357 return nullptr; 1358 } 1359 mGPUChild->SendInitAPZInputBridge(aRootLayerTreeId, std::move(parentPipe)); 1360 1361 RefPtr<APZInputBridgeChild> inputBridge = 1362 APZInputBridgeChild::Create(mProcessToken, std::move(childPipe)); 1363 if (!inputBridge) { 1364 return nullptr; 1365 } 1366 1367 apz->SetInputBridge(inputBridge); 1368 } 1369 1370 return new RemoteCompositorSession(aWidget, child, widget, apz, 1371 aRootLayerTreeId); 1372 #else 1373 gfxCriticalNote << "Platform does not support out-of-process compositing"; 1374 return nullptr; 1375 #endif 1376 } 1377 1378 bool GPUProcessManager::CreateContentBridges( 1379 ipc::EndpointProcInfo aOtherProcess, 1380 ipc::Endpoint<PCompositorManagerChild>* aOutCompositor, 1381 ipc::Endpoint<PImageBridgeChild>* aOutImageBridge, 1382 ipc::Endpoint<PVRManagerChild>* aOutVRBridge, 1383 ipc::Endpoint<PRemoteMediaManagerChild>* aOutVideoManager, 1384 dom::ContentParentId aChildId, nsTArray<uint32_t>* aNamespaces) { 1385 const uint32_t cmNamespace = AllocateNamespace(); 1386 if (!CreateContentCompositorManager(aOtherProcess, aChildId, cmNamespace, 1387 aOutCompositor) || 1388 !CreateContentImageBridge(aOtherProcess, aChildId, aOutImageBridge) || 1389 !CreateContentVRManager(aOtherProcess, aChildId, aOutVRBridge)) { 1390 return false; 1391 } 1392 // RemoteMediaManager is only supported in the GPU process, so we allow this 1393 // to be fallible. 1394 CreateContentRemoteMediaManager(aOtherProcess, aChildId, aOutVideoManager); 1395 // Allocates 3 namespaces(for CompositorManagerChild, CompositorBridgeChild 1396 // and ImageBridgeChild) 1397 aNamespaces->AppendElement(cmNamespace); 1398 aNamespaces->AppendElement(AllocateNamespace()); 1399 aNamespaces->AppendElement(AllocateNamespace()); 1400 return true; 1401 } 1402 1403 bool GPUProcessManager::CreateContentCompositorManager( 1404 ipc::EndpointProcInfo aOtherProcess, dom::ContentParentId aChildId, 1405 uint32_t aNamespace, ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint) { 1406 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 1407 1408 ipc::Endpoint<PCompositorManagerParent> parentPipe; 1409 ipc::Endpoint<PCompositorManagerChild> childPipe; 1410 1411 ipc::EndpointProcInfo parentInfo = mGPUChild 1412 ? mGPUChild->OtherEndpointProcInfo() 1413 : ipc::EndpointProcInfo::Current(); 1414 1415 nsresult rv = PCompositorManager::CreateEndpoints(parentInfo, aOtherProcess, 1416 &parentPipe, &childPipe); 1417 if (NS_FAILED(rv)) { 1418 gfxCriticalNote << "Could not create content compositor manager: " 1419 << hexa(int(rv)); 1420 return false; 1421 } 1422 1423 if (mGPUChild) { 1424 mGPUChild->SendNewContentCompositorManager(std::move(parentPipe), aChildId, 1425 aNamespace); 1426 } else if (!CompositorManagerParent::Create(std::move(parentPipe), aChildId, 1427 aNamespace, 1428 /* aIsRoot */ false)) { 1429 return false; 1430 } 1431 1432 *aOutEndpoint = std::move(childPipe); 1433 return true; 1434 } 1435 1436 bool GPUProcessManager::CreateContentImageBridge( 1437 ipc::EndpointProcInfo aOtherProcess, dom::ContentParentId aChildId, 1438 ipc::Endpoint<PImageBridgeChild>* aOutEndpoint) { 1439 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 1440 1441 if (!EnsureImageBridgeChild()) { 1442 return false; 1443 } 1444 1445 ipc::EndpointProcInfo parentInfo = mGPUChild 1446 ? mGPUChild->OtherEndpointProcInfo() 1447 : ipc::EndpointProcInfo::Current(); 1448 1449 ipc::Endpoint<PImageBridgeParent> parentPipe; 1450 ipc::Endpoint<PImageBridgeChild> childPipe; 1451 nsresult rv = PImageBridge::CreateEndpoints(parentInfo, aOtherProcess, 1452 &parentPipe, &childPipe); 1453 if (NS_FAILED(rv)) { 1454 gfxCriticalNote << "Could not create content compositor bridge: " 1455 << hexa(int(rv)); 1456 return false; 1457 } 1458 1459 if (mGPUChild) { 1460 mGPUChild->SendNewContentImageBridge(std::move(parentPipe), aChildId); 1461 } else { 1462 if (!ImageBridgeParent::CreateForContent(std::move(parentPipe), aChildId)) { 1463 return false; 1464 } 1465 } 1466 1467 *aOutEndpoint = std::move(childPipe); 1468 return true; 1469 } 1470 1471 base::ProcessId GPUProcessManager::GPUProcessPid() { 1472 base::ProcessId gpuPid = 1473 mGPUChild ? mGPUChild->OtherPid() : base::kInvalidProcessId; 1474 return gpuPid; 1475 } 1476 1477 ipc::EndpointProcInfo GPUProcessManager::GPUEndpointProcInfo() { 1478 return mGPUChild ? mGPUChild->OtherEndpointProcInfo() 1479 : ipc::EndpointProcInfo::Invalid(); 1480 } 1481 1482 bool GPUProcessManager::CreateContentVRManager( 1483 ipc::EndpointProcInfo aOtherProcess, dom::ContentParentId aChildId, 1484 ipc::Endpoint<PVRManagerChild>* aOutEndpoint) { 1485 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 1486 1487 if (NS_WARN_IF(!EnsureVRManager())) { 1488 return false; 1489 } 1490 1491 ipc::EndpointProcInfo parentInfo = mGPUChild 1492 ? mGPUChild->OtherEndpointProcInfo() 1493 : ipc::EndpointProcInfo::Current(); 1494 1495 ipc::Endpoint<PVRManagerParent> parentPipe; 1496 ipc::Endpoint<PVRManagerChild> childPipe; 1497 nsresult rv = PVRManager::CreateEndpoints(parentInfo, aOtherProcess, 1498 &parentPipe, &childPipe); 1499 if (NS_FAILED(rv)) { 1500 gfxCriticalNote << "Could not create content compositor bridge: " 1501 << hexa(int(rv)); 1502 return false; 1503 } 1504 1505 if (mGPUChild) { 1506 mGPUChild->SendNewContentVRManager(std::move(parentPipe), aChildId); 1507 } else { 1508 if (!VRManagerParent::CreateForContent(std::move(parentPipe), aChildId)) { 1509 return false; 1510 } 1511 } 1512 1513 *aOutEndpoint = std::move(childPipe); 1514 return true; 1515 } 1516 1517 void GPUProcessManager::CreateContentRemoteMediaManager( 1518 ipc::EndpointProcInfo aOtherProcess, dom::ContentParentId aChildId, 1519 ipc::Endpoint<PRemoteMediaManagerChild>* aOutEndpoint) { 1520 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 1521 1522 if (!mGPUChild || !StaticPrefs::media_gpu_process_decoder() || 1523 !mDecodeVideoOnGpuProcess) { 1524 return; 1525 } 1526 1527 ipc::Endpoint<PRemoteMediaManagerParent> parentPipe; 1528 ipc::Endpoint<PRemoteMediaManagerChild> childPipe; 1529 1530 nsresult rv = PRemoteMediaManager::CreateEndpoints( 1531 mGPUChild->OtherEndpointProcInfo(), aOtherProcess, &parentPipe, 1532 &childPipe); 1533 if (NS_FAILED(rv)) { 1534 gfxCriticalNote << "Could not create content video decoder: " 1535 << hexa(int(rv)); 1536 return; 1537 } 1538 1539 mGPUChild->SendNewContentRemoteMediaManager(std::move(parentPipe), aChildId); 1540 1541 *aOutEndpoint = std::move(childPipe); 1542 } 1543 1544 #ifdef MOZ_WMF_MEDIA_ENGINE 1545 nsresult GPUProcessManager::CreateUtilityMFCDMVideoBridge( 1546 mozilla::ipc::UtilityMediaServiceChild* aChild, 1547 mozilla::ipc::EndpointProcInfo aOtherProcess) { 1548 MOZ_ASSERT(aChild); 1549 MOZ_ASSERT(aChild->CanSend()); 1550 1551 ipc::Endpoint<PVideoBridgeChild> childPipe; 1552 nsresult rv = EnsureVideoBridge(VideoBridgeSource::MFMediaEngineCDMProcess, 1553 aOtherProcess, &childPipe); 1554 if (NS_WARN_IF(NS_FAILED(rv))) { 1555 return rv; 1556 } 1557 1558 gfx::ContentDeviceData contentDeviceData; 1559 gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData); 1560 aChild->SendInitVideoBridge(std::move(childPipe), contentDeviceData); 1561 return NS_OK; 1562 } 1563 #endif 1564 1565 nsresult GPUProcessManager::CreateRddVideoBridge(RDDProcessManager* aRDD, 1566 RDDChild* aChild) { 1567 MOZ_ASSERT(aRDD); 1568 MOZ_ASSERT(aChild); 1569 MOZ_ASSERT(aChild->CanSend()); 1570 1571 ipc::Endpoint<PVideoBridgeChild> childPipe; 1572 nsresult rv = EnsureVideoBridge(VideoBridgeSource::RddProcess, 1573 aChild->OtherEndpointProcInfo(), &childPipe); 1574 if (NS_WARN_IF(NS_FAILED(rv))) { 1575 return rv; 1576 } 1577 1578 gfx::ContentDeviceData contentDeviceData; 1579 gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData); 1580 aChild->SendInitVideoBridge(std::move(childPipe), 1581 !aRDD->AttemptedRDDProcess(), contentDeviceData); 1582 return NS_OK; 1583 } 1584 1585 nsresult GPUProcessManager::EnsureVideoBridge( 1586 layers::VideoBridgeSource aSource, 1587 mozilla::ipc::EndpointProcInfo aOtherProcess, 1588 mozilla::ipc::Endpoint<layers::PVideoBridgeChild>* aOutChildPipe) { 1589 MOZ_ASSERT(aOutChildPipe); 1590 MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); 1591 1592 ipc::EndpointProcInfo gpuInfo = mGPUChild ? mGPUChild->OtherEndpointProcInfo() 1593 : ipc::EndpointProcInfo::Current(); 1594 1595 // The child end is the producer of video frames; the parent end is the 1596 // consumer. 1597 ipc::Endpoint<PVideoBridgeParent> parentPipe; 1598 nsresult rv = PVideoBridge::CreateEndpoints(gpuInfo, aOtherProcess, 1599 &parentPipe, aOutChildPipe); 1600 if (NS_WARN_IF(NS_FAILED(rv))) { 1601 return rv; 1602 } 1603 1604 if (mGPUChild) { 1605 mGPUChild->SendInitVideoBridge(std::move(parentPipe), aSource); 1606 } else { 1607 VideoBridgeParent::Open(std::move(parentPipe), aSource); 1608 } 1609 return NS_OK; 1610 } 1611 1612 void GPUProcessManager::UnmapLayerTreeId(LayersId aLayersId, 1613 base::ProcessId aOwningId) { 1614 // If the GPU process is down, but not disabled, there is no need to relaunch 1615 // here because the layers ID is already invalid. 1616 if (mGPUChild) { 1617 mGPUChild->SendRemoveLayerTreeIdMapping( 1618 LayerTreeIdMapping(aLayersId, aOwningId)); 1619 } else if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { 1620 CompositorBridgeParent::DeallocateLayerTreeId(aLayersId); 1621 } 1622 1623 LayerTreeOwnerTracker::Get()->Unmap(aLayersId, aOwningId); 1624 } 1625 1626 bool GPUProcessManager::IsLayerTreeIdMapped(LayersId aLayersId, 1627 base::ProcessId aRequestingId) { 1628 return LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, aRequestingId); 1629 } 1630 1631 LayersId GPUProcessManager::AllocateLayerTreeId() { 1632 // Allocate tree id by using id namespace. 1633 // By it, tree id does not conflict with external image id and 1634 // async image pipeline id. 1635 MOZ_ASSERT(NS_IsMainThread()); 1636 // Increment the resource id by two instead of one so that each 1637 // WebRenderLayerManager and WebRenderBridgeParent gets two distinct 1638 // pipeline IDs they can use. 1639 // This is gross but the steps to create a temporary pipeline 1640 // ID from the content process or the compositor thread are too 1641 // complex and expensive. 1642 // TODO: Ideally, we'd allocate only the namespace here and let the 1643 // WR layer manager produce any number of pipeline IDs. 1644 mResourceId += 2; 1645 if (mResourceId >= UINT32_MAX - 1) { 1646 // Move to next id namespace. 1647 mIdNamespace = AllocateNamespace(); 1648 mResourceId = 2; 1649 } 1650 1651 uint64_t layerTreeId = mIdNamespace; 1652 layerTreeId = (layerTreeId << 32) | mResourceId; 1653 return LayersId{layerTreeId}; 1654 } 1655 1656 // See the comment in AllocateLayerTreeId above. 1657 // For now this is only used for view-transition snapshots of the old state, 1658 // it's probably best to avoid using this for anything else. 1659 wr::PipelineId GetTemporaryWebRenderPipelineId(wr::PipelineId aMainPipeline) { 1660 // Sanity check that we are have the expected even number for 1661 // the main pipeline handle. 1662 MOZ_ASSERT(aMainPipeline.mHandle % 2 == 0); 1663 auto id = aMainPipeline; 1664 id.mHandle += 1; 1665 return id; 1666 } 1667 1668 uint32_t GPUProcessManager::AllocateNamespace() { 1669 MOZ_ASSERT(NS_IsMainThread()); 1670 return ++mNextNamespace; 1671 } 1672 1673 bool GPUProcessManager::AllocateAndConnectLayerTreeId( 1674 PCompositorBridgeChild* aCompositorBridge, base::ProcessId aOtherPid, 1675 LayersId* aOutLayersId, CompositorOptions* aOutCompositorOptions) { 1676 MOZ_ASSERT(aOutLayersId); 1677 1678 LayersId layersId = AllocateLayerTreeId(); 1679 *aOutLayersId = layersId; 1680 1681 // We always map the layer ID in the parent process so that we can recover 1682 // from GPU process crashes. In that case, the tree will be shared with the 1683 // new GPU process at initialization. 1684 LayerTreeOwnerTracker::Get()->Map(layersId, aOtherPid); 1685 1686 if (NS_WARN_IF(NS_FAILED(EnsureGPUReady()))) { 1687 return false; 1688 } 1689 1690 // If we have a CompositorBridgeChild, then we need to call 1691 // CompositorBridgeParent::NotifyChildCreated. If this is in the GPU process, 1692 // we can combine it with LayerTreeOwnerTracker::Map to minimize IPC. 1693 // messages. 1694 if (aCompositorBridge) { 1695 if (mGPUChild) { 1696 return aCompositorBridge->SendMapAndNotifyChildCreated( 1697 layersId, aOtherPid, aOutCompositorOptions); 1698 } 1699 return aCompositorBridge->SendNotifyChildCreated(layersId, 1700 aOutCompositorOptions); 1701 } 1702 1703 // If we don't have a CompositorBridgeChild, we just need to call 1704 // LayerTreeOwnerTracker::Map in the compositing process. 1705 if (mGPUChild) { 1706 mGPUChild->SendAddLayerTreeIdMapping( 1707 LayerTreeIdMapping(layersId, aOtherPid)); 1708 } 1709 return false; 1710 } 1711 1712 void GPUProcessManager::EnsureVsyncIOThread() { 1713 if (mVsyncIOThread) { 1714 return; 1715 } 1716 1717 mVsyncIOThread = new VsyncIOThreadHolder(); 1718 MOZ_RELEASE_ASSERT(mVsyncIOThread->Start()); 1719 } 1720 1721 void GPUProcessManager::ShutdownVsyncIOThread() { mVsyncIOThread = nullptr; } 1722 1723 void GPUProcessManager::RegisterRemoteProcessSession( 1724 RemoteCompositorSession* aSession) { 1725 mRemoteSessions.AppendElement(aSession); 1726 } 1727 1728 void GPUProcessManager::UnregisterRemoteProcessSession( 1729 RemoteCompositorSession* aSession) { 1730 mRemoteSessions.RemoveElement(aSession); 1731 } 1732 1733 void GPUProcessManager::RegisterInProcessSession( 1734 InProcessCompositorSession* aSession) { 1735 mInProcessSessions.AppendElement(aSession); 1736 } 1737 1738 void GPUProcessManager::UnregisterInProcessSession( 1739 InProcessCompositorSession* aSession) { 1740 mInProcessSessions.RemoveElement(aSession); 1741 } 1742 1743 void GPUProcessManager::AddListener(GPUProcessListener* aListener) { 1744 if (!mListeners.Contains(aListener)) { 1745 mListeners.AppendElement(aListener); 1746 } 1747 } 1748 1749 void GPUProcessManager::RemoveListener(GPUProcessListener* aListener) { 1750 mListeners.RemoveElement(aListener); 1751 } 1752 1753 bool GPUProcessManager::NotifyGpuObservers(const char* aTopic) { 1754 if (mGPUChild) { 1755 nsCString topic(aTopic); 1756 mGPUChild->SendNotifyGpuObservers(topic); 1757 return true; 1758 } 1759 1760 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { 1761 nsCOMPtr<nsIObserverService> obsSvc = 1762 mozilla::services::GetObserverService(); 1763 MOZ_ASSERT(obsSvc); 1764 if (obsSvc) { 1765 obsSvc->NotifyObservers(nullptr, aTopic, nullptr); 1766 } 1767 return true; 1768 } 1769 1770 // If we still are using a GPU process, but do not have one ready at the 1771 // moment, we can drop these notifications since there is nothing to do. 1772 return false; 1773 } 1774 1775 class GPUMemoryReporter : public MemoryReportingProcess { 1776 public: 1777 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GPUMemoryReporter, override) 1778 1779 bool IsAlive() const override { 1780 if (GPUProcessManager* gpm = GPUProcessManager::Get()) { 1781 return !!gpm->GetGPUChild(); 1782 } 1783 return false; 1784 } 1785 1786 bool SendRequestMemoryReport( 1787 const uint32_t& aGeneration, const bool& aAnonymize, 1788 const bool& aMinimizeMemoryUsage, 1789 const Maybe<ipc::FileDescriptor>& aDMDFile) override { 1790 GPUChild* child = GetChild(); 1791 if (!child) { 1792 return false; 1793 } 1794 1795 return child->SendRequestMemoryReport(aGeneration, aAnonymize, 1796 aMinimizeMemoryUsage, aDMDFile); 1797 } 1798 1799 int32_t Pid() const override { 1800 if (GPUChild* child = GetChild()) { 1801 return (int32_t)child->OtherPid(); 1802 } 1803 return 0; 1804 } 1805 1806 private: 1807 GPUChild* GetChild() const { 1808 if (GPUProcessManager* gpm = GPUProcessManager::Get()) { 1809 return gpm->GetGPUChild(); 1810 } 1811 return nullptr; 1812 } 1813 1814 protected: 1815 ~GPUMemoryReporter() = default; 1816 }; 1817 1818 RefPtr<MemoryReportingProcess> GPUProcessManager::GetProcessMemoryReporter() { 1819 // If we are in the middle of launching a GPU process, we can wait for it to 1820 // finish, otherwise if there is no GPU process, we should just return now to 1821 // avoid launching it again. 1822 if (!mProcess || AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown) || 1823 !mProcess->WaitForLaunch()) { 1824 return nullptr; 1825 } 1826 return MakeRefPtr<GPUMemoryReporter>(); 1827 } 1828 1829 void GPUProcessManager::SetAppInForeground(bool aInForeground) { 1830 if (mAppInForeground == aInForeground) { 1831 return; 1832 } 1833 1834 mAppInForeground = aInForeground; 1835 #if defined(XP_WIN) 1836 SetProcessIsForeground(); 1837 #endif 1838 1839 // If we moved into the foreground, then we need to make sure the GPU process 1840 // completes its launch. Otherwise listeners may be left dangling from 1841 // previous calls that returned NS_ERROR_ABORT due to being in the background. 1842 if (aInForeground && gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { 1843 (void)LaunchGPUProcess(); 1844 } 1845 } 1846 1847 #if defined(XP_WIN) 1848 void GPUProcessManager::SetProcessIsForeground() { 1849 NTSTATUS WINAPI NtSetInformationProcess( 1850 IN HANDLE process_handle, IN ULONG info_class, 1851 IN PVOID process_information, IN ULONG information_length); 1852 constexpr unsigned int NtProcessInformationForeground = 25; 1853 1854 static bool alreadyInitialized = false; 1855 static decltype(NtSetInformationProcess)* setInformationProcess = nullptr; 1856 if (!alreadyInitialized) { 1857 alreadyInitialized = true; 1858 nsModuleHandle module(LoadLibrary(L"ntdll.dll")); 1859 if (module) { 1860 setInformationProcess = 1861 (decltype(NtSetInformationProcess)*)GetProcAddress( 1862 module, "NtSetInformationProcess"); 1863 } 1864 } 1865 if (MOZ_UNLIKELY(!setInformationProcess)) { 1866 return; 1867 } 1868 1869 unsigned pid = GPUProcessPid(); 1870 if (pid <= 0) { 1871 return; 1872 } 1873 // Using the handle from mProcess->GetChildProcessHandle() fails; 1874 // the PROCESS_SET_INFORMATION permission is probably missing. 1875 nsAutoHandle processHandle( 1876 ::OpenProcess(PROCESS_SET_INFORMATION, FALSE, pid)); 1877 if (!processHandle) { 1878 return; 1879 } 1880 1881 BOOLEAN foreground = mAppInForeground; 1882 setInformationProcess(processHandle, NtProcessInformationForeground, 1883 (PVOID)&foreground, sizeof(foreground)); 1884 } 1885 #endif 1886 1887 RefPtr<PGPUChild::TestTriggerMetricsPromise> 1888 GPUProcessManager::TestTriggerMetrics() { 1889 if (!NS_WARN_IF(!mGPUChild)) { 1890 return mGPUChild->SendTestTriggerMetrics(); 1891 } 1892 1893 return PGPUChild::TestTriggerMetricsPromise::CreateAndReject( 1894 ipc::ResponseRejectReason::SendError, __func__); 1895 } 1896 1897 } // namespace gfx 1898 } // namespace mozilla