commit 8fbbb50184640ff2f7fbaad5382da08656fabbde
parent a24e64c61e6b6f00e04af6e075fe737479338fc0
Author: Andrew Osmond <aosmond@gmail.com>
Date: Mon, 20 Oct 2025 03:23:37 +0000
Bug 1993758 - Rework how RDD/utility processes initialize PVideoBridge with the GPU process. r=gfx-reviewers,lsalzman
This avoids calls to GPUProcessManager::EnsureGPUReady as well as making
it more manageable to avoid relaunching the GPU process while in the
background on Android.
Differential Revision: https://phabricator.services.mozilla.com/D269115
Diffstat:
10 files changed, 142 insertions(+), 125 deletions(-)
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
@@ -2786,12 +2786,15 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
xpcomInit.userContentSheetURL() = nullptr;
}
- // 1. Build ContentDeviceData first, as it may affect some gfxVars.
+ // 1. Ensure the GPU process is ready, as we know we are not yet in shutdown.
+ GPUProcessManager* gpm = GPUProcessManager::Get();
+ gpm->EnsureGPUReady();
+ // 2. Build ContentDeviceData first, as it may affect some gfxVars.
gfxPlatform::GetPlatform()->BuildContentDeviceData(
&xpcomInit.contentDeviceData());
- // 2. Gather non-default gfxVars.
+ // 3. Gather non-default gfxVars.
xpcomInit.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars();
- // 3. Start listening for gfxVars updates, to notify content process later on.
+ // 4. Start listening for gfxVars updates, to notify content process later on.
gfxVars::AddReceiver(this);
nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
@@ -2905,8 +2908,6 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
// PBrowsers are created, because they rely on the Compositor
// already being around. (Creation is async, so can't happen
// on demand.)
- GPUProcessManager* gpm = GPUProcessManager::Get();
-
Endpoint<PCompositorManagerChild> compositor;
Endpoint<PImageBridgeChild> imageBridge;
Endpoint<PVRManagerChild> vrBridge;
diff --git a/dom/media/ipc/RDDChild.cpp b/dom/media/ipc/RDDChild.cpp
@@ -72,10 +72,6 @@ bool RDDChild::Init() {
Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
gfxVars::AddReceiver(this);
- auto* gpm = gfx::GPUProcessManager::Get();
- if (gpm) {
- gpm->AddListener(this);
- }
return true;
}
@@ -110,9 +106,14 @@ bool RDDChild::SendRequestMemoryReport(const uint32_t& aGeneration,
}
void RDDChild::OnCompositorUnexpectedShutdown() {
- auto* rddm = RDDProcessManager::Get();
- if (rddm) {
- rddm->CreateVideoBridge();
+ if (!CanSend()) {
+ return;
+ }
+
+ if (RDDProcessManager* rddpm = RDDProcessManager::Get()) {
+ if (auto* gpm = GPUProcessManager::Get()) {
+ gpm->CreateRddVideoBridge(rddpm, this);
+ }
}
}
@@ -207,8 +208,7 @@ void RDDChild::ActorDestroy(ActorDestroyReason aWhy) {
GenerateCrashReport();
}
- auto* gpm = gfx::GPUProcessManager::Get();
- if (gpm) {
+ if (auto* gpm = gfx::GPUProcessManager::Get()) {
// Note: the manager could have shutdown already.
gpm->RemoveListener(this);
}
diff --git a/dom/media/ipc/RDDProcessManager.cpp b/dom/media/ipc/RDDProcessManager.cpp
@@ -173,12 +173,17 @@ RefPtr<GenericNonExclusivePromise> RDDProcessManager::LaunchRDDProcess() {
CrashReporter::RecordAnnotationCString(
CrashReporter::Annotation::RDDProcessStatus, "Running");
- if (!CreateVideoBridge()) {
+ auto* gpm = GPUProcessManager::Get();
+ if (NS_WARN_IF(!mRDDChild->CanSend()) || NS_WARN_IF(!gpm) ||
+ NS_WARN_IF(NS_FAILED(gpm->EnsureGPUReady())) ||
+ NS_WARN_IF(NS_FAILED(gpm->CreateRddVideoBridge(this, mRDDChild)))) {
mNumProcessAttempts++;
DestroyProcess();
return GenericNonExclusivePromise::CreateAndReject(
NS_ERROR_NOT_AVAILABLE, __func__);
}
+
+ gpm->AddListener(mRDDChild);
return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
},
[this](nsresult aError) {
@@ -304,50 +309,6 @@ bool RDDProcessManager::CreateContentBridge(
return true;
}
-bool RDDProcessManager::CreateVideoBridge() {
- MOZ_ASSERT(NS_IsMainThread());
- ipc::Endpoint<PVideoBridgeParent> parentPipe;
- ipc::Endpoint<PVideoBridgeChild> childPipe;
-
- GPUProcessManager* gpuManager = GPUProcessManager::Get();
- ipc::EndpointProcInfo gpuProcessInfo = gpuManager
- ? gpuManager->GPUEndpointProcInfo()
- : ipc::EndpointProcInfo::Invalid();
-
- // Build content device data first; this ensure that the GPU process is fully
- // ready.
- ContentDeviceData contentDeviceData;
- gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData);
-
- // The child end is the producer of video frames; the parent end is the
- // consumer.
- ipc::EndpointProcInfo childInfo = RDDEndpointProcInfo();
- ipc::EndpointProcInfo parentInfo =
- gpuProcessInfo != ipc::EndpointProcInfo::Invalid()
- ? gpuProcessInfo
- : ipc::EndpointProcInfo::Current();
-
- nsresult rv = PVideoBridge::CreateEndpoints(parentInfo, childInfo,
- &parentPipe, &childPipe);
- if (NS_FAILED(rv)) {
- MOZ_LOG(sPDMLog, LogLevel::Debug,
- ("Could not create video bridge: %d", int(rv)));
- return false;
- }
-
- mRDDChild->SendInitVideoBridge(std::move(childPipe),
- mNumUnexpectedCrashes == 0, contentDeviceData);
- if (gpuProcessInfo != ipc::EndpointProcInfo::Invalid()) {
- gpuManager->InitVideoBridge(std::move(parentPipe),
- VideoBridgeSource::RddProcess);
- } else {
- VideoBridgeParent::Open(std::move(parentPipe),
- VideoBridgeSource::RddProcess);
- }
-
- return true;
-}
-
base::ProcessId RDDProcessManager::RDDProcessPid() {
MOZ_ASSERT(NS_IsMainThread());
base::ProcessId rddPid =
diff --git a/dom/media/ipc/RDDProcessManager.h b/dom/media/ipc/RDDProcessManager.h
@@ -76,7 +76,6 @@ class RDDProcessManager final : public RDDProcessHost::Listener {
private:
bool IsRDDProcessLaunching();
bool IsRDDProcessDestroyed() const;
- bool CreateVideoBridge();
// Called from our xpcom-shutdown observer.
void OnXPCOMShutdown();
diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp
@@ -13,13 +13,15 @@
#include "mozilla/AppShutdown.h"
#include "mozilla/MemoryReportingProcess.h"
#include "mozilla/Preferences.h"
+#include "mozilla/RDDChild.h"
+#include "mozilla/RDDProcessManager.h"
+#include "mozilla/RemoteMediaManagerChild.h"
+#include "mozilla/RemoteMediaManagerParent.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/StaticPrefs_media.h"
-#include "mozilla/RemoteMediaManagerChild.h"
-#include "mozilla/RemoteMediaManagerParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUChild.h"
@@ -39,6 +41,7 @@
#include "mozilla/layers/InProcessCompositorSession.h"
#include "mozilla/layers/LayerTreeOwnerTracker.h"
#include "mozilla/layers/RemoteCompositorSession.h"
+#include "mozilla/layers/VideoBridgeParent.h"
#include "mozilla/webrender/RenderThread.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsAppRunner.h"
@@ -56,6 +59,10 @@
#include "nsExceptionHandler.h"
#include "nsPrintfCString.h"
+#ifdef MOZ_WMF_MEDIA_ENGINE
+# include "mozilla/ipc/UtilityMediaServiceChild.h"
+#endif
+
#if defined(MOZ_WIDGET_ANDROID)
# include "mozilla/java/SurfaceControlManagerWrappers.h"
# include "mozilla/widget/AndroidUiThread.h"
@@ -1511,16 +1518,72 @@ void GPUProcessManager::CreateContentRemoteMediaManager(
*aOutEndpoint = std::move(childPipe);
}
-void GPUProcessManager::InitVideoBridge(
- ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge,
- layers::VideoBridgeSource aSource) {
- if (NS_WARN_IF(NS_FAILED(EnsureGPUReady()))) {
- return;
+#ifdef MOZ_WMF_MEDIA_ENGINE
+nsresult GPUProcessManager::CreateUtilityMFCDMVideoBridge(
+ mozilla::ipc::UtilityMediaServiceChild* aChild,
+ mozilla::ipc::EndpointProcInfo aOtherProcess) {
+ MOZ_ASSERT(aChild);
+ MOZ_ASSERT(aChild->CanSend());
+
+ ipc::Endpoint<PVideoBridgeChild> childPipe;
+ nsresult rv = EnsureVideoBridge(VideoBridgeSource::MFMediaEngineCDMProcess,
+ aOtherProcess, &childPipe);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ gfx::ContentDeviceData contentDeviceData;
+ gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData);
+ aChild->SendInitVideoBridge(std::move(childPipe), contentDeviceData);
+ return NS_OK;
+}
+#endif
+
+nsresult GPUProcessManager::CreateRddVideoBridge(RDDProcessManager* aRDD,
+ RDDChild* aChild) {
+ MOZ_ASSERT(aRDD);
+ MOZ_ASSERT(aChild);
+ MOZ_ASSERT(aChild->CanSend());
+
+ ipc::Endpoint<PVideoBridgeChild> childPipe;
+ nsresult rv = EnsureVideoBridge(VideoBridgeSource::RddProcess,
+ aChild->OtherEndpointProcInfo(), &childPipe);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ gfx::ContentDeviceData contentDeviceData;
+ gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData);
+ aChild->SendInitVideoBridge(std::move(childPipe),
+ !aRDD->AttemptedRDDProcess(), contentDeviceData);
+ return NS_OK;
+}
+
+nsresult GPUProcessManager::EnsureVideoBridge(
+ layers::VideoBridgeSource aSource,
+ mozilla::ipc::EndpointProcInfo aOtherProcess,
+ mozilla::ipc::Endpoint<layers::PVideoBridgeChild>* aOutChildPipe) {
+ MOZ_ASSERT(aOutChildPipe);
+ MOZ_DIAGNOSTIC_ASSERT(IsGPUReady());
+
+ ipc::EndpointProcInfo gpuInfo = mGPUChild ? mGPUChild->OtherEndpointProcInfo()
+ : ipc::EndpointProcInfo::Current();
+
+ // The child end is the producer of video frames; the parent end is the
+ // consumer.
+ ipc::Endpoint<PVideoBridgeParent> parentPipe;
+ nsresult rv = PVideoBridge::CreateEndpoints(gpuInfo, aOtherProcess,
+ &parentPipe, aOutChildPipe);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
}
if (mGPUChild) {
- mGPUChild->SendInitVideoBridge(std::move(aVideoBridge), aSource);
+ mGPUChild->SendInitVideoBridge(std::move(parentPipe), aSource);
+ } else {
+ VideoBridgeParent::Open(std::move(parentPipe), aSource);
}
+ return NS_OK;
}
void GPUProcessManager::MapLayerTreeId(LayersId aLayersId,
diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h
@@ -27,6 +27,8 @@ enum class DeviceResetReason;
namespace mozilla {
class MemoryReportingProcess;
class PRemoteMediaManagerChild;
+class RDDProcessManager;
+class RDDChild;
namespace layers {
class IAPZCTreeManager;
class CompositorOptions;
@@ -50,6 +52,9 @@ class BrowserParent;
} // namespace dom
namespace ipc {
class GeckoChildProcessHost;
+#ifdef MOZ_WMF_MEDIA_ENGINE
+class UtilityMediaServiceChild;
+#endif
} // namespace ipc
namespace gfx {
@@ -105,6 +110,8 @@ class GPUProcessManager final : public GPUProcessHost::Listener {
// in shutdown.
nsresult EnsureGPUReady();
+ bool IsGPUReady() const;
+
already_AddRefed<CompositorSession> CreateTopLevelCompositor(
nsIWidget* aWidget, WebRenderLayerManager* aLayerManager,
CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
@@ -119,10 +126,12 @@ class GPUProcessManager final : public GPUProcessHost::Listener {
mozilla::ipc::Endpoint<PRemoteMediaManagerChild>* aOutVideoManager,
dom::ContentParentId aChildId, nsTArray<uint32_t>* aNamespaces);
- // Initialize GPU process with consuming end of PVideoBridge.
- void InitVideoBridge(
- mozilla::ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge,
- layers::VideoBridgeSource aSource);
+ nsresult CreateRddVideoBridge(RDDProcessManager* aRDD, RDDChild* aChild);
+#ifdef MOZ_WMF_MEDIA_ENGINE
+ nsresult CreateUtilityMFCDMVideoBridge(
+ mozilla::ipc::UtilityMediaServiceChild* aChild,
+ mozilla::ipc::EndpointProcInfo aOtherProcess);
+#endif
// Maps the layer tree and process together so that aOwningPID is allowed
// to access aLayersId across process.
@@ -235,8 +244,6 @@ class GPUProcessManager final : public GPUProcessHost::Listener {
void OnPreferenceChange(const char16_t* aData);
void ScreenInformationChanged();
- bool IsGPUReady() const;
-
bool CreateContentCompositorManager(
mozilla::ipc::EndpointProcInfo aOtherProcess,
dom::ContentParentId aChildId, uint32_t aNamespace,
@@ -254,6 +261,11 @@ class GPUProcessManager final : public GPUProcessHost::Listener {
dom::ContentParentId aChildId,
mozilla::ipc::Endpoint<PRemoteMediaManagerChild>* aOutEndPoint);
+ nsresult EnsureVideoBridge(
+ layers::VideoBridgeSource aSource,
+ mozilla::ipc::EndpointProcInfo aOtherProcess,
+ mozilla::ipc::Endpoint<layers::PVideoBridgeChild>* aOutChildPipe);
+
// Called from RemoteCompositorSession. We track remote sessions so we can
// notify their owning widgets that the session must be restarted.
void RegisterRemoteProcessSession(RemoteCompositorSession* aSession);
diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp
@@ -4163,9 +4163,11 @@ void gfxPlatform::BuildContentDeviceData(
mozilla::gfx::ContentDeviceData* aOut) {
MOZ_ASSERT(XRE_IsParentProcess());
- // Make sure our settings are synchronized from the GPU process.
- DebugOnly<nsresult> rv = GPUProcessManager::Get()->EnsureGPUReady();
- MOZ_ASSERT(NS_SUCCEEDED(rv));
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ if (auto* gpm = GPUProcessManager::Get()) {
+ MOZ_DIAGNOSTIC_ASSERT(gpm->IsGPUReady());
+ }
+#endif
aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
aOut->prefs().oglCompositing() =
diff --git a/ipc/glue/UtilityMediaServiceChild.cpp b/ipc/glue/UtilityMediaServiceChild.cpp
@@ -88,6 +88,12 @@ nsresult UtilityMediaServiceChild::BindToUtilityProcess(
void UtilityMediaServiceChild::ActorDestroy(ActorDestroyReason aReason) {
MOZ_ASSERT(NS_IsMainThread());
gfx::gfxVars::RemoveReceiver(this);
+#ifdef MOZ_WMF_MEDIA_ENGINE
+ if (auto* gpm = gfx::GPUProcessManager::Get()) {
+ // Note: the manager could have shutdown already.
+ gpm->RemoveListener(this);
+ }
+#endif
Shutdown(mSandbox);
}
@@ -144,60 +150,33 @@ void UtilityMediaServiceChild::OnCompositorUnexpectedShutdown() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM);
mHasCreatedVideoBridge = State::None;
- CreateVideoBridge();
+
+ if (auto* gpm = gfx::GPUProcessManager::Get()) {
+ if (auto utilpm = UtilityProcessManager::GetSingleton())
+ if (auto parent = utilpm->GetProcessParent(mSandbox)) {
+ if (NS_SUCCEEDED(gpm->CreateUtilityMFCDMVideoBridge(
+ this, parent->OtherEndpointProcInfo()))) {
+ mHasCreatedVideoBridge = State::Creating;
+ }
+ }
+ }
}
-bool UtilityMediaServiceChild::CreateVideoBridge() {
+bool UtilityMediaServiceChild::CreateVideoBridge(
+ mozilla::ipc::EndpointProcInfo aOtherProcess) {
MOZ_ASSERT(NS_IsMainThread());
- ipc::Endpoint<layers::PVideoBridgeParent> parentPipe;
- ipc::Endpoint<layers::PVideoBridgeChild> childPipe;
-
MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM);
+ MOZ_ASSERT(mHasCreatedVideoBridge == State::None);
- // Creating or already created, avoiding reinit a bridge.
- if (mHasCreatedVideoBridge != State::None) {
- return true;
- }
- mHasCreatedVideoBridge = State::Creating;
-
- gfx::GPUProcessManager* gpuManager = gfx::GPUProcessManager::Get();
- ipc::EndpointProcInfo gpuProcessInfo = gpuManager
- ? gpuManager->GPUEndpointProcInfo()
- : ipc::EndpointProcInfo::Invalid();
-
- // Build content device data first; this ensure that the GPU process is fully
- // ready.
- gfx::ContentDeviceData contentDeviceData;
- gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData);
-
- // The child end is the producer of video frames; the parent end is the
- // consumer.
- EndpointProcInfo childInfo = UtilityProcessManager::GetSingleton()
- ->GetProcessParent(mSandbox)
- ->OtherEndpointProcInfo();
- EndpointProcInfo parentInfo =
- gpuProcessInfo != ipc::EndpointProcInfo::Invalid()
- ? gpuProcessInfo
- : ipc::EndpointProcInfo::Current();
-
- nsresult rv = layers::PVideoBridge::CreateEndpoints(parentInfo, childInfo,
- &parentPipe, &childPipe);
- if (NS_FAILED(rv)) {
- NS_WARNING("Failed to create endpoints for video bridge!");
+ auto* gpm = gfx::GPUProcessManager::Get();
+ if (NS_WARN_IF(!gpm) || NS_WARN_IF(NS_FAILED(gpm->EnsureGPUReady())) ||
+ NS_WARN_IF(
+ NS_FAILED(gpm->CreateUtilityMFCDMVideoBridge(this, aOtherProcess)))) {
return false;
}
- if (gpuProcessInfo != ipc::EndpointProcInfo::Invalid()) {
- gpuManager->InitVideoBridge(
- std::move(parentPipe),
- layers::VideoBridgeSource::MFMediaEngineCDMProcess);
- } else {
- layers::VideoBridgeParent::Open(
- std::move(parentPipe),
- layers::VideoBridgeSource::MFMediaEngineCDMProcess);
- }
-
- SendInitVideoBridge(std::move(childPipe), contentDeviceData);
+ gpm->AddListener(this);
+ mHasCreatedVideoBridge = State::Creating;
return true;
}
#endif
diff --git a/ipc/glue/UtilityMediaServiceChild.h b/ipc/glue/UtilityMediaServiceChild.h
@@ -77,7 +77,7 @@ class UtilityMediaServiceChild final : public PUtilityMediaServiceChild,
// True if creating a video bridge sucessfully. Currently only used for media
// engine cdm.
- bool CreateVideoBridge();
+ bool CreateVideoBridge(mozilla::ipc::EndpointProcInfo aOtherProcess);
#endif
#ifdef MOZ_WMF_CDM
diff --git a/ipc/glue/UtilityProcessManager.cpp b/ipc/glue/UtilityProcessManager.cpp
@@ -385,7 +385,7 @@ UtilityProcessManager::StartProcessForRemoteMediaDecoding(
#ifdef MOZ_WMF_MEDIA_ENGINE
if (aSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM &&
- !umsc->CreateVideoBridge()) {
+ !umsc->CreateVideoBridge(process)) {
MOZ_ASSERT(false, "Failed to create video bridge");
return RetPromise::CreateAndReject(
LaunchError("UMSC::CreateVideoBridge"), __func__);