2016-07-18 04:24:28 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2017-10-27 23:10:06 +00:00
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2016-05-23 07:27:01 +00:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2017-02-14 22:01:59 +00:00
|
|
|
|
2016-05-23 07:27:01 +00:00
|
|
|
#include "GPUProcessManager.h"
|
2017-02-14 22:01:59 +00:00
|
|
|
|
2020-04-05 03:50:33 +00:00
|
|
|
#include "gfxConfig.h"
|
2020-12-10 14:26:32 +00:00
|
|
|
#include "gfxPlatform.h"
|
2016-06-11 02:27:24 +00:00
|
|
|
#include "GPUProcessHost.h"
|
2016-09-20 08:18:50 +00:00
|
|
|
#include "GPUProcessListener.h"
|
2022-04-11 11:49:21 +00:00
|
|
|
#include "mozilla/AppShutdown.h"
|
2017-01-27 00:35:54 +00:00
|
|
|
#include "mozilla/MemoryReportingProcess.h"
|
2019-05-25 10:12:51 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
2016-11-15 18:58:29 +00:00
|
|
|
#include "mozilla/Sprintf.h"
|
2016-07-18 04:24:28 +00:00
|
|
|
#include "mozilla/StaticPtr.h"
|
2019-07-26 01:10:23 +00:00
|
|
|
#include "mozilla/StaticPrefs_gfx.h"
|
|
|
|
#include "mozilla/StaticPrefs_layers.h"
|
|
|
|
#include "mozilla/StaticPrefs_media.h"
|
2019-06-11 02:01:34 +00:00
|
|
|
#include "mozilla/RemoteDecoderManagerChild.h"
|
|
|
|
#include "mozilla/RemoteDecoderManagerParent.h"
|
2020-04-05 03:50:33 +00:00
|
|
|
#include "mozilla/Telemetry.h"
|
2016-08-16 20:59:13 +00:00
|
|
|
#include "mozilla/dom/ContentParent.h"
|
Bug 1354411 - Rebuild CompositorSessions if WebRender is disabled r=kats
When WebRender creation is failed, WebRender is disabled in gecko. There is a case that WebRenderBridgeParents exist when WebRender is disabled. To handle this, gecko needs to rebuild all CompositorSessions.
There is also a problem related to gfxVars::UseWebRender on compositor thread. If e10s is enabled, but no-gpu process(default on linux and mac), gfxVars::UseWebRender change is soon notified by compositor thread tasks. If WebRender creation failure happens at 2nd WebRender creation, several WebRenderBridgeParents for 1st WebRender could exist. IPC messages from WebRenderLayerManager are normally async, then there is a chance that the WebRenderBridgeParents receive the messages after the gfxVars::UseWebRender change. Further the gfxVars::UseWebRender change in content process could be delayed than WebRenderBridgeParents, then content process does not have a way to stop sending PWebRenderBridge IPC until the change of gfxVars::UseWebRender is received. WebRenderBridgeParent related tasks handle the message, but some tasks are done based on gfxVars::UseWebRender. At this time, gfxVars::UseWebRender returned false on compositor thread, then it cause unexpected result for WebRenderBridgeParent and WebRender. To addres this inconsistent situation, WebRenderBridgeParent related tasks on compositor thread stop to use gfxVars::UseWebRender.
2017-08-04 05:36:41 +00:00
|
|
|
#include "mozilla/gfx/gfxVars.h"
|
2020-04-05 03:50:33 +00:00
|
|
|
#include "mozilla/gfx/GPUChild.h"
|
2020-11-23 16:06:42 +00:00
|
|
|
#include "mozilla/ipc/Endpoint.h"
|
2021-10-26 19:42:03 +00:00
|
|
|
#include "mozilla/ipc/ProcessChild.h"
|
2016-08-29 13:18:00 +00:00
|
|
|
#include "mozilla/layers/APZCTreeManagerChild.h"
|
2020-04-05 03:50:33 +00:00
|
|
|
#include "mozilla/layers/APZInputBridgeChild.h"
|
|
|
|
#include "mozilla/layers/CompositorBridgeChild.h"
|
2016-07-18 04:24:28 +00:00
|
|
|
#include "mozilla/layers/CompositorBridgeParent.h"
|
2017-06-14 15:39:59 +00:00
|
|
|
#include "mozilla/layers/CompositorManagerChild.h"
|
|
|
|
#include "mozilla/layers/CompositorManagerParent.h"
|
2017-01-12 22:29:41 +00:00
|
|
|
#include "mozilla/layers/CompositorOptions.h"
|
2016-07-20 07:17:28 +00:00
|
|
|
#include "mozilla/layers/ImageBridgeChild.h"
|
2016-07-20 07:18:30 +00:00
|
|
|
#include "mozilla/layers/ImageBridgeParent.h"
|
2016-07-18 04:24:28 +00:00
|
|
|
#include "mozilla/layers/InProcessCompositorSession.h"
|
2016-08-16 20:59:13 +00:00
|
|
|
#include "mozilla/layers/LayerTreeOwnerTracker.h"
|
2016-07-18 04:24:28 +00:00
|
|
|
#include "mozilla/layers/RemoteCompositorSession.h"
|
2022-03-08 23:14:28 +00:00
|
|
|
#include "mozilla/webrender/RenderThread.h"
|
2016-07-18 04:24:28 +00:00
|
|
|
#include "mozilla/widget/PlatformWidgetTypes.h"
|
2018-05-08 14:31:52 +00:00
|
|
|
#include "nsAppRunner.h"
|
2021-11-19 02:44:22 +00:00
|
|
|
#include "mozilla/widget/CompositorWidget.h"
|
2016-07-18 04:24:28 +00:00
|
|
|
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
|
|
|
|
# include "mozilla/widget/CompositorWidgetChild.h"
|
|
|
|
#endif
|
2016-07-19 18:56:07 +00:00
|
|
|
#include "nsBaseWidget.h"
|
2016-06-11 02:27:24 +00:00
|
|
|
#include "nsContentUtils.h"
|
2016-07-21 07:14:59 +00:00
|
|
|
#include "VRManagerChild.h"
|
2016-07-21 07:14:59 +00:00
|
|
|
#include "VRManagerParent.h"
|
2016-07-19 18:56:06 +00:00
|
|
|
#include "VsyncBridgeChild.h"
|
|
|
|
#include "VsyncIOThreadHolder.h"
|
2016-07-26 08:57:11 +00:00
|
|
|
#include "VsyncSource.h"
|
2017-10-10 13:11:07 +00:00
|
|
|
#include "nsExceptionHandler.h"
|
2017-07-13 17:27:00 +00:00
|
|
|
#include "nsPrintfCString.h"
|
2016-05-23 07:27:01 +00:00
|
|
|
|
2017-01-05 19:04:38 +00:00
|
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
Bug 1767128 - Rework and re-enable SurfaceControl rendering path on Android. r=agi,gfx-reviewers,aosmond
In bug 1762424 we introduced a rendering path on Android using the
SurfaceControl API, in order to work around a bug preventing recovery
from a GPU process crash. However, the initial implementation caused
this bug: repeatedly sending the same SurfaceControl objects over AIDL
to the GPU process resulted in them being leaked, eventually causing
severe display issues. Not only were we duplicating the SurfaceControl
for each widget, but each time a widget was resized too.
This patch reworks our usage of the SurfaceControl API to avoid ever
having to send them cross-process. Instead, we create a single child
SurfaceControl object for each SurfaceControl that is attached to a
widget. (Typically there will be a single one shared between all
widgets, changing only when the app is paused and resumed, which is
much fewer than one per widget per resize.)
In the parent process we obtain the Surfaces that will be rendered in
to from the child SurfaceControls, and only send those Surfaces to the
GPU process. Thankfully unlike SurfaceControls, sending Surfaces
cross-process does not cause leaks. When the GPU process dies we
simply destroy all of the child SurfaceControls, and recreate them
again on-demand.
Differential Revision: https://phabricator.services.mozilla.com/D147437
2022-05-31 18:41:07 +00:00
|
|
|
# include "mozilla/java/SurfaceControlManagerWrappers.h"
|
2017-01-05 19:04:38 +00:00
|
|
|
# include "mozilla/widget/AndroidUiThread.h"
|
|
|
|
# include "mozilla/layers/UiCompositorControllerChild.h"
|
|
|
|
#endif // defined(MOZ_WIDGET_ANDROID)
|
|
|
|
|
2021-11-16 08:25:09 +00:00
|
|
|
#if defined(XP_WIN)
|
|
|
|
# include "gfxWindowsPlatform.h"
|
|
|
|
#endif
|
|
|
|
|
2016-05-23 07:27:01 +00:00
|
|
|
namespace mozilla {
|
|
|
|
namespace gfx {
|
|
|
|
|
|
|
|
using namespace mozilla::layers;
|
|
|
|
|
2017-04-14 21:36:42 +00:00
|
|
|
enum class FallbackType : uint32_t {
|
|
|
|
NONE = 0,
|
|
|
|
DECODINGDISABLED,
|
|
|
|
DISABLED,
|
|
|
|
};
|
|
|
|
|
2016-05-23 07:27:01 +00:00
|
|
|
static StaticAutoPtr<GPUProcessManager> sSingleton;
|
|
|
|
|
|
|
|
GPUProcessManager* GPUProcessManager::Get() { return sSingleton; }
|
|
|
|
|
|
|
|
void GPUProcessManager::Initialize() {
|
2016-06-27 06:33:20 +00:00
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
2016-05-23 07:27:01 +00:00
|
|
|
sSingleton = new GPUProcessManager();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::Shutdown() { sSingleton = nullptr; }
|
|
|
|
|
|
|
|
GPUProcessManager::GPUProcessManager()
|
2016-07-18 04:24:28 +00:00
|
|
|
: mTaskFactory(this),
|
2017-04-14 08:06:09 +00:00
|
|
|
mNextNamespace(0),
|
2017-05-30 00:59:44 +00:00
|
|
|
mIdNamespace(0),
|
|
|
|
mResourceId(0),
|
2021-05-06 19:47:38 +00:00
|
|
|
mUnstableProcessAttempts(0),
|
|
|
|
mTotalProcessAttempts(0),
|
2016-11-10 02:57:04 +00:00
|
|
|
mDeviceResetCount(0),
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
mAppInForeground(true),
|
2016-07-18 04:24:27 +00:00
|
|
|
mProcess(nullptr),
|
2017-11-16 10:31:51 +00:00
|
|
|
mProcessToken(0),
|
2021-05-06 19:47:38 +00:00
|
|
|
mProcessStable(true),
|
2016-09-28 20:54:03 +00:00
|
|
|
mGPUChild(nullptr) {
|
2016-10-07 07:07:10 +00:00
|
|
|
MOZ_COUNT_CTOR(GPUProcessManager);
|
|
|
|
|
2017-05-30 00:59:44 +00:00
|
|
|
mIdNamespace = AllocateNamespace();
|
2016-08-16 20:59:13 +00:00
|
|
|
|
2016-11-10 02:57:04 +00:00
|
|
|
mDeviceResetLastTime = TimeStamp::Now();
|
|
|
|
|
2016-08-16 20:59:13 +00:00
|
|
|
LayerTreeOwnerTracker::Initialize();
|
2020-01-15 20:22:29 +00:00
|
|
|
CompositorBridgeParent::InitializeStatics();
|
2016-05-23 07:27:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GPUProcessManager::~GPUProcessManager() {
|
2016-10-07 07:07:10 +00:00
|
|
|
MOZ_COUNT_DTOR(GPUProcessManager);
|
|
|
|
|
2016-08-16 20:59:13 +00:00
|
|
|
LayerTreeOwnerTracker::Shutdown();
|
|
|
|
|
2016-06-11 02:27:24 +00:00
|
|
|
// The GPU process should have already been shut down.
|
|
|
|
MOZ_ASSERT(!mProcess && !mGPUChild);
|
|
|
|
|
|
|
|
// We should have already removed observers.
|
|
|
|
MOZ_ASSERT(!mObserver);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(GPUProcessManager::Observer, nsIObserver);
|
|
|
|
|
|
|
|
GPUProcessManager::Observer::Observer(GPUProcessManager* aManager)
|
|
|
|
: mManager(aManager) {}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
GPUProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
const char16_t* aData) {
|
|
|
|
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
|
|
|
mManager->OnXPCOMShutdown();
|
2019-05-25 10:12:51 +00:00
|
|
|
} else if (!strcmp(aTopic, "nsPref:changed")) {
|
|
|
|
mManager->OnPreferenceChange(aData);
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
} else if (!strcmp(aTopic, "application-foreground")) {
|
|
|
|
mManager->mAppInForeground = true;
|
|
|
|
if (!mManager->mProcess && gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
|
2022-04-11 11:49:21 +00:00
|
|
|
Unused << mManager->LaunchGPUProcess();
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
}
|
|
|
|
} else if (!strcmp(aTopic, "application-background")) {
|
|
|
|
mManager->mAppInForeground = false;
|
2016-06-11 02:27:24 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::OnXPCOMShutdown() {
|
|
|
|
if (mObserver) {
|
|
|
|
nsContentUtils::UnregisterShutdownObserver(mObserver);
|
2019-05-25 10:12:51 +00:00
|
|
|
Preferences::RemoveObserver(mObserver, "");
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
|
|
|
|
if (obsServ) {
|
|
|
|
obsServ->RemoveObserver(mObserver, "application-foreground");
|
|
|
|
obsServ->RemoveObserver(mObserver, "application-background");
|
|
|
|
}
|
2016-06-11 02:27:24 +00:00
|
|
|
mObserver = nullptr;
|
|
|
|
}
|
|
|
|
|
2016-07-19 18:56:06 +00:00
|
|
|
CleanShutdown();
|
2016-06-11 02:27:24 +00:00
|
|
|
}
|
|
|
|
|
2019-05-25 10:12:51 +00:00
|
|
|
void GPUProcessManager::OnPreferenceChange(const char16_t* aData) {
|
2022-02-07 16:44:18 +00:00
|
|
|
// We know prefs are ASCII here.
|
|
|
|
NS_LossyConvertUTF16toASCII strData(aData);
|
|
|
|
|
2022-04-27 12:57:34 +00:00
|
|
|
mozilla::dom::Pref pref(strData, /* isLocked */ false,
|
|
|
|
/* isSanitized */ false, Nothing(), Nothing());
|
2022-04-27 12:57:36 +00:00
|
|
|
|
|
|
|
Preferences::GetPreference(&pref, GeckoProcessType_GPU,
|
|
|
|
/* remoteType */ ""_ns);
|
2019-05-25 10:12:51 +00:00
|
|
|
if (!!mGPUChild) {
|
|
|
|
MOZ_ASSERT(mQueuedPrefs.IsEmpty());
|
|
|
|
mGPUChild->SendPreferenceUpdate(pref);
|
2020-02-18 15:57:14 +00:00
|
|
|
} else if (IsGPUProcessLaunching()) {
|
2019-05-25 10:12:51 +00:00
|
|
|
mQueuedPrefs.AppendElement(pref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-20 17:02:55 +00:00
|
|
|
void GPUProcessManager::ResetProcessStable() {
|
|
|
|
mTotalProcessAttempts++;
|
|
|
|
mProcessStable = false;
|
|
|
|
mProcessAttemptLastTime = TimeStamp::Now();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GPUProcessManager::IsProcessStable(const TimeStamp& aNow) {
|
|
|
|
if (mTotalProcessAttempts > 0) {
|
|
|
|
auto delta = (int32_t)(aNow - mProcessAttemptLastTime).ToMilliseconds();
|
|
|
|
if (delta < StaticPrefs::layers_gpu_process_stable_min_uptime_ms()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mProcessStable;
|
|
|
|
}
|
|
|
|
|
2022-04-11 11:49:21 +00:00
|
|
|
bool GPUProcessManager::LaunchGPUProcess() {
|
2016-06-11 02:27:24 +00:00
|
|
|
if (mProcess) {
|
2022-04-11 11:49:21 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown)) {
|
|
|
|
return false;
|
2016-06-11 02:27:24 +00:00
|
|
|
}
|
|
|
|
|
2020-02-18 15:57:14 +00:00
|
|
|
// Start listening for pref changes so we can
|
|
|
|
// forward them to the process once it is running.
|
|
|
|
if (!mObserver) {
|
|
|
|
mObserver = new Observer(this);
|
|
|
|
nsContentUtils::RegisterShutdownObserver(mObserver);
|
|
|
|
Preferences::AddStrongObserver(mObserver, "");
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
|
|
|
|
if (obsServ) {
|
|
|
|
obsServ->AddObserver(mObserver, "application-foreground", false);
|
|
|
|
obsServ->AddObserver(mObserver, "application-background", false);
|
|
|
|
}
|
2020-02-18 15:57:14 +00:00
|
|
|
}
|
|
|
|
|
2016-07-19 18:56:06 +00:00
|
|
|
// Start the Vsync I/O thread so can use it as soon as the process launches.
|
|
|
|
EnsureVsyncIOThread();
|
|
|
|
|
2021-05-06 19:47:38 +00:00
|
|
|
// If the process didn't live long enough, reset the stable flag so that we
|
|
|
|
// don't end up in a restart loop.
|
|
|
|
auto newTime = TimeStamp::Now();
|
2022-10-24 14:53:41 +00:00
|
|
|
if (!IsProcessStable(newTime)) {
|
2021-05-06 19:47:38 +00:00
|
|
|
mUnstableProcessAttempts++;
|
|
|
|
}
|
|
|
|
mTotalProcessAttempts++;
|
2022-05-20 17:02:55 +00:00
|
|
|
mProcessAttemptLastTime = newTime;
|
2021-05-06 19:47:38 +00:00
|
|
|
mProcessStable = false;
|
2016-09-30 08:21:21 +00:00
|
|
|
|
2018-05-08 14:31:52 +00:00
|
|
|
std::vector<std::string> extraArgs;
|
2021-10-26 19:42:03 +00:00
|
|
|
ipc::ProcessChild::AddPlatformBuildID(extraArgs);
|
2018-05-08 14:31:52 +00:00
|
|
|
|
2016-06-11 02:27:24 +00:00
|
|
|
// The subprocess is launched asynchronously, so we wait for a callback to
|
|
|
|
// acquire the IPDL actor.
|
|
|
|
mProcess = new GPUProcessHost(this);
|
2018-05-08 14:31:52 +00:00
|
|
|
if (!mProcess->Launch(extraArgs)) {
|
2016-06-11 02:27:24 +00:00
|
|
|
DisableGPUProcess("Failed to launch GPU process");
|
|
|
|
}
|
2022-04-11 11:49:21 +00:00
|
|
|
|
|
|
|
return true;
|
2016-06-11 02:27:24 +00:00
|
|
|
}
|
|
|
|
|
2020-02-18 15:57:14 +00:00
|
|
|
bool GPUProcessManager::IsGPUProcessLaunching() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return !!mProcess && !mGPUChild;
|
|
|
|
}
|
|
|
|
|
2016-06-11 02:27:24 +00:00
|
|
|
void GPUProcessManager::DisableGPUProcess(const char* aMessage) {
|
2021-02-01 23:36:36 +00:00
|
|
|
MaybeDisableGPUProcess(aMessage, /* aAllowRestart */ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GPUProcessManager::MaybeDisableGPUProcess(const char* aMessage,
|
|
|
|
bool aAllowRestart) {
|
2016-09-30 08:21:21 +00:00
|
|
|
if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
|
2021-02-01 23:36:36 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-05-05 14:31:46 +00:00
|
|
|
if (!aAllowRestart) {
|
|
|
|
gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, aMessage);
|
|
|
|
}
|
|
|
|
|
2022-05-20 17:02:55 +00:00
|
|
|
bool wantRestart;
|
|
|
|
if (mLastError) {
|
|
|
|
wantRestart =
|
|
|
|
FallbackFromAcceleration(mLastError.value(), mLastErrorMsg.ref());
|
|
|
|
mLastError.reset();
|
|
|
|
mLastErrorMsg.reset();
|
|
|
|
} else {
|
|
|
|
wantRestart = gfxPlatform::FallbackFromAcceleration(
|
|
|
|
FeatureStatus::Unavailable, "GPU Process is disabled",
|
|
|
|
"FEATURE_FAILURE_GPU_PROCESS_DISABLED"_ns);
|
|
|
|
}
|
2021-02-01 23:36:36 +00:00
|
|
|
if (aAllowRestart && wantRestart) {
|
|
|
|
// The fallback method can make use of the GPU process.
|
|
|
|
return false;
|
2016-09-30 08:21:21 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 14:31:46 +00:00
|
|
|
if (aAllowRestart) {
|
|
|
|
gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, aMessage);
|
|
|
|
}
|
|
|
|
|
2016-06-11 02:27:24 +00:00
|
|
|
gfxCriticalNote << aMessage;
|
|
|
|
|
2021-02-01 23:36:36 +00:00
|
|
|
gfxPlatform::DisableGPUProcess();
|
2017-02-09 06:33:54 +00:00
|
|
|
|
2017-04-14 21:36:42 +00:00
|
|
|
Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
|
|
|
|
uint32_t(FallbackType::DISABLED));
|
|
|
|
|
2016-06-11 02:27:24 +00:00
|
|
|
DestroyProcess();
|
2016-07-19 18:56:06 +00:00
|
|
|
ShutdownVsyncIOThread();
|
2017-06-28 18:31:42 +00:00
|
|
|
|
2022-05-20 17:02:55 +00:00
|
|
|
// Now the stability state is based upon the in process compositor session.
|
|
|
|
ResetProcessStable();
|
|
|
|
|
2017-06-28 18:31:42 +00:00
|
|
|
// We may have been in the middle of guaranteeing our various services are
|
|
|
|
// available when one failed. Some callers may fallback to using the same
|
|
|
|
// process equivalent, and we need to make sure those services are setup
|
|
|
|
// correctly. We cannot re-enter DisableGPUProcess from this call because we
|
|
|
|
// know that it is disabled in the config above.
|
|
|
|
EnsureProtocolsReady();
|
2017-07-20 13:20:22 +00:00
|
|
|
|
|
|
|
// If we disable the GPU process during reinitialization after a previous
|
|
|
|
// crash, then we need to tell the content processes again, because they
|
|
|
|
// need to rebind to the UI process.
|
|
|
|
HandleProcessLost();
|
2021-02-01 23:36:36 +00:00
|
|
|
return true;
|
2016-06-11 02:27:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GPUProcessManager::EnsureGPUReady() {
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
// Launch the GPU process if it is enabled but hasn't been (re-)launched yet.
|
|
|
|
if (!mProcess && gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
|
2022-04-11 11:49:21 +00:00
|
|
|
if (!LaunchGPUProcess()) {
|
|
|
|
return false;
|
|
|
|
}
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 23:03:41 +00:00
|
|
|
if (mProcess && !mProcess->IsConnected()) {
|
2016-06-11 02:27:24 +00:00
|
|
|
if (!mProcess->WaitForLaunch()) {
|
|
|
|
// If this fails, we should have fired OnProcessLaunchComplete and
|
|
|
|
// removed the process.
|
|
|
|
MOZ_ASSERT(!mProcess && !mGPUChild);
|
2017-03-30 01:23:24 +00:00
|
|
|
return false;
|
2016-06-11 02:27:24 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-21 03:59:11 +00:00
|
|
|
|
2018-01-30 17:58:57 +00:00
|
|
|
if (mGPUChild) {
|
|
|
|
if (mGPUChild->EnsureGPUReady()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the initialization above fails, we likely have a GPU process teardown
|
|
|
|
// waiting in our message queue (or will soon). We need to ensure we don't
|
|
|
|
// restart it later because if we fail here, our callers assume they should
|
|
|
|
// fall back to a combined UI/GPU process. This also ensures our internal
|
|
|
|
// state is consistent (e.g. process token is reset).
|
|
|
|
DisableGPUProcess("Failed to initialize GPU process");
|
2016-08-21 03:59:11 +00:00
|
|
|
}
|
2017-03-30 01:23:24 +00:00
|
|
|
|
2022-05-20 17:02:55 +00:00
|
|
|
// This is the first time we are trying to use the in-process compositor.
|
|
|
|
if (mTotalProcessAttempts == 0) {
|
|
|
|
ResetProcessStable();
|
|
|
|
}
|
2017-03-30 01:23:24 +00:00
|
|
|
return false;
|
2016-06-11 02:27:24 +00:00
|
|
|
}
|
|
|
|
|
2017-06-28 18:31:42 +00:00
|
|
|
void GPUProcessManager::EnsureProtocolsReady() {
|
|
|
|
EnsureCompositorManagerChild();
|
|
|
|
EnsureImageBridgeChild();
|
|
|
|
EnsureVRManager();
|
|
|
|
}
|
|
|
|
|
2017-06-14 15:39:59 +00:00
|
|
|
void GPUProcessManager::EnsureCompositorManagerChild() {
|
2017-09-26 17:21:52 +00:00
|
|
|
bool gpuReady = EnsureGPUReady();
|
|
|
|
if (CompositorManagerChild::IsInitialized(mProcessToken)) {
|
2017-06-14 15:39:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-26 17:21:52 +00:00
|
|
|
if (!gpuReady) {
|
|
|
|
CompositorManagerChild::InitSameProcess(AllocateNamespace(), mProcessToken);
|
2017-06-14 15:39:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipc::Endpoint<PCompositorManagerParent> parentPipe;
|
|
|
|
ipc::Endpoint<PCompositorManagerChild> childPipe;
|
|
|
|
nsresult rv = PCompositorManager::CreateEndpoints(
|
|
|
|
mGPUChild->OtherPid(), base::GetCurrentProcId(), &parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
DisableGPUProcess("Failed to create PCompositorManager endpoints");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
mGPUChild->SendInitCompositorManager(std::move(parentPipe));
|
|
|
|
CompositorManagerChild::Init(std::move(childPipe), AllocateNamespace(),
|
2017-09-26 17:21:52 +00:00
|
|
|
mProcessToken);
|
2017-06-14 15:39:59 +00:00
|
|
|
}
|
|
|
|
|
2016-07-20 07:17:28 +00:00
|
|
|
void GPUProcessManager::EnsureImageBridgeChild() {
|
2016-09-13 23:30:57 +00:00
|
|
|
if (ImageBridgeChild::GetSingleton()) {
|
2016-07-20 07:19:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-30 01:23:24 +00:00
|
|
|
if (!EnsureGPUReady()) {
|
2017-04-14 08:06:09 +00:00
|
|
|
ImageBridgeChild::InitSameProcess(AllocateNamespace());
|
2016-07-20 07:19:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipc::Endpoint<PImageBridgeParent> parentPipe;
|
|
|
|
ipc::Endpoint<PImageBridgeChild> childPipe;
|
|
|
|
nsresult rv = PImageBridge::CreateEndpoints(
|
|
|
|
mGPUChild->OtherPid(), base::GetCurrentProcId(), &parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
DisableGPUProcess("Failed to create PImageBridge endpoints");
|
|
|
|
return;
|
2016-07-20 07:17:28 +00:00
|
|
|
}
|
2016-07-20 07:19:27 +00:00
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
mGPUChild->SendInitImageBridge(std::move(parentPipe));
|
|
|
|
ImageBridgeChild::InitWithGPUProcess(std::move(childPipe),
|
|
|
|
AllocateNamespace());
|
2016-07-20 07:17:28 +00:00
|
|
|
}
|
|
|
|
|
2016-07-21 07:14:59 +00:00
|
|
|
void GPUProcessManager::EnsureVRManager() {
|
|
|
|
if (VRManagerChild::IsCreated()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-30 01:23:24 +00:00
|
|
|
if (!EnsureGPUReady()) {
|
2016-07-21 07:14:59 +00:00
|
|
|
VRManagerChild::InitSameProcess();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipc::Endpoint<PVRManagerParent> parentPipe;
|
|
|
|
ipc::Endpoint<PVRManagerChild> childPipe;
|
|
|
|
nsresult rv = PVRManager::CreateEndpoints(
|
|
|
|
mGPUChild->OtherPid(), base::GetCurrentProcId(), &parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
DisableGPUProcess("Failed to create PVRManager endpoints");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
mGPUChild->SendInitVRManager(std::move(parentPipe));
|
|
|
|
VRManagerChild::InitWithGPUProcess(std::move(childPipe));
|
2016-07-21 07:14:59 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 19:04:38 +00:00
|
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
2017-04-05 22:42:50 +00:00
|
|
|
already_AddRefed<UiCompositorControllerChild>
|
2018-03-24 23:06:01 +00:00
|
|
|
GPUProcessManager::CreateUiCompositorController(nsBaseWidget* aWidget,
|
|
|
|
const LayersId aId) {
|
2017-04-05 22:42:50 +00:00
|
|
|
RefPtr<UiCompositorControllerChild> result;
|
2017-01-05 19:04:38 +00:00
|
|
|
|
2017-03-30 01:23:24 +00:00
|
|
|
if (!EnsureGPUReady()) {
|
Bug 1756700 - Delay compositor creation on Android to allow time for GPU process to launch. r=gfx-reviewers,geckoview-reviewers,aosmond,calu
We noticed a cold_view_nav_start regression on Fenix from enabling the
GPU process, and profiles showed time spent synchronously waiting for
the GPU process to launch. This occured because the compositor was
being created in nsWindow::Create, and as it requires the GPU process
to be running it had to block until launch completed. The process is
launched when the gfxPlatform is first initialized, but that was only
occuring immediately prior to creating the compositor, which did not
give it enough time to complete asynchronously.
This patch makes it so that we initialize the gfxPlatform slightly
earlier, and importantly delay creating the compositor until it is
actually required. This gives the process enough time to launch
asynchronously meaning we do not have to block.
We started deliberately creating the compositor early on Android
because of bug 1453501, to avoid a race condition where the compositor
didn't exist when RemoteLayerTreeOwner::Initialize was called, causing
us to use a basic layer manager. However, since bug 1741156 landed we
now create the compositor on-demand, meaning this is no longer a
possibility.
Delaying compositor creation can, however, uncover another race
condition. If the UICompositorControllerChild is opened on the UI
thread before the main thread is able to set its pointer to the
widget, then the java GeckoSession will never be notified that the
compositor has been opened, and composition will never be
resumed. This patch fixes this issue by setting the
UiCompositorControllerChild's widget pointer in its constructor rather
than immediately afterwards.
Differential Revision: https://phabricator.services.mozilla.com/D139842
2022-03-02 16:56:28 +00:00
|
|
|
result = UiCompositorControllerChild::CreateForSameProcess(aId, aWidget);
|
2017-04-05 22:42:50 +00:00
|
|
|
} else {
|
|
|
|
ipc::Endpoint<PUiCompositorControllerParent> parentPipe;
|
|
|
|
ipc::Endpoint<PUiCompositorControllerChild> childPipe;
|
|
|
|
nsresult rv = PUiCompositorController::CreateEndpoints(
|
|
|
|
mGPUChild->OtherPid(), base::GetCurrentProcId(), &parentPipe,
|
|
|
|
&childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
DisableGPUProcess("Failed to create PUiCompositorController endpoints");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-01-05 19:04:38 +00:00
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
mGPUChild->SendInitUiCompositorController(aId, std::move(parentPipe));
|
|
|
|
result = UiCompositorControllerChild::CreateForGPUProcess(
|
Bug 1756700 - Delay compositor creation on Android to allow time for GPU process to launch. r=gfx-reviewers,geckoview-reviewers,aosmond,calu
We noticed a cold_view_nav_start regression on Fenix from enabling the
GPU process, and profiles showed time spent synchronously waiting for
the GPU process to launch. This occured because the compositor was
being created in nsWindow::Create, and as it requires the GPU process
to be running it had to block until launch completed. The process is
launched when the gfxPlatform is first initialized, but that was only
occuring immediately prior to creating the compositor, which did not
give it enough time to complete asynchronously.
This patch makes it so that we initialize the gfxPlatform slightly
earlier, and importantly delay creating the compositor until it is
actually required. This gives the process enough time to launch
asynchronously meaning we do not have to block.
We started deliberately creating the compositor early on Android
because of bug 1453501, to avoid a race condition where the compositor
didn't exist when RemoteLayerTreeOwner::Initialize was called, causing
us to use a basic layer manager. However, since bug 1741156 landed we
now create the compositor on-demand, meaning this is no longer a
possibility.
Delaying compositor creation can, however, uncover another race
condition. If the UICompositorControllerChild is opened on the UI
thread before the main thread is able to set its pointer to the
widget, then the java GeckoSession will never be notified that the
compositor has been opened, and composition will never be
resumed. This patch fixes this issue by setting the
UiCompositorControllerChild's widget pointer in its constructor rather
than immediately afterwards.
Differential Revision: https://phabricator.services.mozilla.com/D139842
2022-03-02 16:56:28 +00:00
|
|
|
mProcessToken, std::move(childPipe), aWidget);
|
Bug 1741156 - Initial GPU process implementation on Android. r=aosmond,agi
Declare a GPU process and corresponding Service in the
AndroidManifest. This is of a new class GeckoServiceGpuProcess which
inherits from GeckoServiceChildProcess, and provides a binder
interface ICompositorSurfaceManager which allows the parent process to
set the compositor Surface for a given widget ID, and the compositor
in the GPU process to look up the Surface for a widget ID. The
ICompositorSurfaceManager interface is exposed to the parent process
through a new method getCompositorSurfaceManager() in the
IChildProcess interface.
Add a new connection type for GPU processes to GeckoProcessManager,
along with a function to look up the GPU process connection and fetch
the ICompositorSurfaceManager binder. When the GPU process is launched
we store the returned binder in the GPUProcessHost, and when each
widget's compositor is created we store a reference to the binder in
the UiCompositorControllerChild.
Each nsWindow is given a unique ID, and whenever the Surface changes
due to an Android resume event, it sends the new surface for that ID
to the GPU process (if enabled) by calling
ICompositorSurfaceManager.onSurfaceChanged().
Stop inheriting AndroidCompositorWidget from InProcessCompositorWidget
and instead inherit from CompositorWidget directly. This class holds a
reference to the Surface that will be rendered in to. The
CompositorBridgeParent notifies the CompositorWidget whenever it has
been resumed, allowing it to fetch the new Surface. For the
cross-process CompositorWidgetParent implementation it fetches that
Surface from the CompositorSurfaceManagerService, whereas the
InProcessAndroidCompositorWidget can read it directly from the real
widget.
AndroidCompositorWidget::GetClientSize() can now calculate its size
from the Surface, rather than racily reading the value from the
nsWindow. This means RenderCompositorEGL and RenderCompositorOGLSWGL
can now use GetClientSize() again rather than querying their own size
from the Surface.
With this patch, setting layers.gpu-process.enabled to true will cause
us to launch a GPU process and render from it. We do not yet
gracefully recover from a GPU process crash, nor can we render
anything using SurfaceTextures (eg video or webgl). Those will come in
future patches.
Differential Revision: https://phabricator.services.mozilla.com/D131231
2021-11-29 20:52:31 +00:00
|
|
|
|
|
|
|
if (result) {
|
|
|
|
result->SetCompositorSurfaceManager(
|
|
|
|
mProcess->GetCompositorSurfaceManager());
|
|
|
|
}
|
2017-01-05 19:04:38 +00:00
|
|
|
}
|
2017-04-05 22:42:50 +00:00
|
|
|
return result.forget();
|
2017-01-05 19:04:38 +00:00
|
|
|
}
|
|
|
|
#endif // defined(MOZ_WIDGET_ANDROID)
|
|
|
|
|
2016-06-11 02:27:24 +00:00
|
|
|
void GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) {
|
|
|
|
MOZ_ASSERT(mProcess && mProcess == aHost);
|
|
|
|
|
|
|
|
if (!mProcess->IsConnected()) {
|
2016-11-11 22:51:25 +00:00
|
|
|
DisableGPUProcess("Failed to connect GPU process");
|
2016-06-11 02:27:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mGPUChild = mProcess->GetActor();
|
2016-07-18 04:24:28 +00:00
|
|
|
mProcessToken = mProcess->GetProcessToken();
|
2016-07-19 18:56:06 +00:00
|
|
|
|
2020-04-05 03:50:33 +00:00
|
|
|
ipc::Endpoint<PVsyncBridgeParent> vsyncParent;
|
|
|
|
ipc::Endpoint<PVsyncBridgeChild> vsyncChild;
|
2016-07-19 18:56:06 +00:00
|
|
|
nsresult rv = PVsyncBridge::CreateEndpoints(mGPUChild->OtherPid(),
|
|
|
|
base::GetCurrentProcId(),
|
|
|
|
&vsyncParent, &vsyncChild);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
DisableGPUProcess("Failed to create PVsyncBridge endpoints");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
mVsyncBridge = VsyncBridgeChild::Create(mVsyncIOThread, mProcessToken,
|
|
|
|
std::move(vsyncChild));
|
|
|
|
mGPUChild->SendInitVsyncBridge(std::move(vsyncParent));
|
2016-11-02 20:55:07 +00:00
|
|
|
|
2019-05-25 10:12:51 +00:00
|
|
|
// Flush any pref updates that happened during launch and weren't
|
|
|
|
// included in the blobs set up in LaunchGPUProcess.
|
|
|
|
for (const mozilla::dom::Pref& pref : mQueuedPrefs) {
|
|
|
|
Unused << NS_WARN_IF(!mGPUChild->SendPreferenceUpdate(pref));
|
|
|
|
}
|
|
|
|
mQueuedPrefs.Clear();
|
|
|
|
|
2017-04-03 22:11:27 +00:00
|
|
|
CrashReporter::AnnotateCrashReport(
|
Bug 1348273 - Convert crash annotations into a machine-readable list of constants; r=ted.mielczarek,njn,dholbert,mak,cpearce,mcmanus,froydnj,Dexter,jrmuizel,jchen,jimm,bz,surkov
This introduces the machinery needed to generate crash annotations from a YAML
file. The relevant C++ functions are updated to take a typed enum. JavaScript
calls are unaffected but they will throw if the string argument does not
correspond to one of the known entries in the C++ enum. The existing whitelists
and blacklists of annotations are also generated from the YAML file and all
duplicate code related to them has been consolidated. Once written out to the
.extra file the annotations are converted in string form and are no different
than the existing ones.
All existing annotations have been included in the list (and some obsolete ones
have been removed) and all call sites have been updated including tests where
appropriate.
--HG--
extra : source : 4f6c43f2830701ec5552e08e3f1b06fe6d045860
2018-07-05 13:42:11 +00:00
|
|
|
CrashReporter::Annotation::GPUProcessStatus, "Running"_ns);
|
2017-07-13 17:27:00 +00:00
|
|
|
|
|
|
|
CrashReporter::AnnotateCrashReport(
|
Bug 1348273 - Convert crash annotations into a machine-readable list of constants; r=ted.mielczarek,njn,dholbert,mak,cpearce,mcmanus,froydnj,Dexter,jrmuizel,jchen,jimm,bz,surkov
This introduces the machinery needed to generate crash annotations from a YAML
file. The relevant C++ functions are updated to take a typed enum. JavaScript
calls are unaffected but they will throw if the string argument does not
correspond to one of the known entries in the C++ enum. The existing whitelists
and blacklists of annotations are also generated from the YAML file and all
duplicate code related to them has been consolidated. Once written out to the
.extra file the annotations are converted in string form and are no different
than the existing ones.
All existing annotations have been included in the list (and some obsolete ones
have been removed) and all call sites have been updated including tests where
appropriate.
--HG--
extra : source : 4f6c43f2830701ec5552e08e3f1b06fe6d045860
2018-07-05 13:42:11 +00:00
|
|
|
CrashReporter::Annotation::GPUProcessLaunchCount,
|
2021-05-06 19:47:38 +00:00
|
|
|
static_cast<int>(mTotalProcessAttempts));
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
|
|
|
|
ReinitializeRendering();
|
2016-06-11 02:27:24 +00:00
|
|
|
}
|
|
|
|
|
2021-05-06 19:47:38 +00:00
|
|
|
void GPUProcessManager::OnProcessDeclaredStable() { mProcessStable = true; }
|
|
|
|
|
2016-11-10 02:57:04 +00:00
|
|
|
static bool ShouldLimitDeviceResets(uint32_t count, int32_t deltaMilliseconds) {
|
|
|
|
// We decide to limit by comparing the amount of resets that have happened
|
2017-06-15 18:34:00 +00:00
|
|
|
// and time since the last reset to two prefs.
|
2019-07-22 02:10:14 +00:00
|
|
|
int32_t timeLimit = StaticPrefs::gfx_device_reset_threshold_ms_AtStartup();
|
|
|
|
int32_t countLimit = StaticPrefs::gfx_device_reset_limit_AtStartup();
|
2016-11-10 02:57:04 +00:00
|
|
|
|
2016-11-14 23:27:14 +00:00
|
|
|
bool hasTimeLimit = timeLimit >= 0;
|
|
|
|
bool hasCountLimit = countLimit >= 0;
|
2016-11-10 02:57:04 +00:00
|
|
|
|
|
|
|
bool triggeredTime = deltaMilliseconds < timeLimit;
|
|
|
|
bool triggeredCount = count > (uint32_t)countLimit;
|
|
|
|
|
|
|
|
// If we have both prefs set then it needs to trigger both limits,
|
|
|
|
// otherwise we only test the pref that is set or none
|
|
|
|
if (hasTimeLimit && hasCountLimit) {
|
|
|
|
return triggeredTime && triggeredCount;
|
|
|
|
} else if (hasTimeLimit) {
|
|
|
|
return triggeredTime;
|
|
|
|
} else if (hasCountLimit) {
|
|
|
|
return triggeredCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-08-11 07:51:23 +00:00
|
|
|
void GPUProcessManager::ResetCompositors() {
|
|
|
|
// Note: this will recreate devices in addition to recreating compositors.
|
|
|
|
// This isn't optimal, but this is only used on linux where acceleration
|
|
|
|
// isn't enabled by default, and this way we don't need a new code path.
|
|
|
|
SimulateDeviceReset();
|
|
|
|
}
|
|
|
|
|
2017-07-11 02:30:52 +00:00
|
|
|
void GPUProcessManager::SimulateDeviceReset() {
|
|
|
|
// Make sure we rebuild environment and configuration for accelerated
|
|
|
|
// features.
|
|
|
|
gfxPlatform::GetPlatform()->CompositorUpdated();
|
|
|
|
|
2017-06-15 18:34:00 +00:00
|
|
|
if (mProcess) {
|
2022-03-08 23:14:28 +00:00
|
|
|
if (mGPUChild) {
|
|
|
|
mGPUChild->SendSimulateDeviceReset();
|
2017-11-03 08:06:37 +00:00
|
|
|
}
|
2017-06-15 18:34:00 +00:00
|
|
|
} else {
|
2022-03-08 23:14:28 +00:00
|
|
|
wr::RenderThread::Get()->SimulateDeviceReset();
|
2017-06-15 18:34:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-20 17:02:55 +00:00
|
|
|
bool GPUProcessManager::FallbackFromAcceleration(wr::WebRenderError aError,
|
|
|
|
const nsCString& aMsg) {
|
2017-08-30 00:10:22 +00:00
|
|
|
if (aError == wr::WebRenderError::INITIALIZE) {
|
2022-05-20 17:02:55 +00:00
|
|
|
return gfxPlatform::FallbackFromAcceleration(
|
2021-02-01 23:36:36 +00:00
|
|
|
gfx::FeatureStatus::Unavailable, "WebRender initialization failed",
|
|
|
|
aMsg);
|
2017-08-30 00:10:22 +00:00
|
|
|
} else if (aError == wr::WebRenderError::MAKE_CURRENT) {
|
2022-05-20 17:02:55 +00:00
|
|
|
return gfxPlatform::FallbackFromAcceleration(
|
2021-02-01 23:36:36 +00:00
|
|
|
gfx::FeatureStatus::Unavailable,
|
|
|
|
"Failed to make render context current",
|
|
|
|
"FEATURE_FAILURE_WEBRENDER_MAKE_CURRENT"_ns);
|
2017-09-01 13:39:28 +00:00
|
|
|
} else if (aError == wr::WebRenderError::RENDER) {
|
2022-05-20 17:02:55 +00:00
|
|
|
return gfxPlatform::FallbackFromAcceleration(
|
2021-02-01 23:36:36 +00:00
|
|
|
gfx::FeatureStatus::Unavailable, "Failed to render WebRender",
|
|
|
|
"FEATURE_FAILURE_WEBRENDER_RENDER"_ns);
|
2019-07-10 11:14:40 +00:00
|
|
|
} else if (aError == wr::WebRenderError::NEW_SURFACE) {
|
2022-04-18 18:11:08 +00:00
|
|
|
// If we cannot create a new Surface even in the final fallback
|
|
|
|
// configuration then force a crash.
|
2022-05-20 17:02:55 +00:00
|
|
|
return gfxPlatform::FallbackFromAcceleration(
|
2021-02-01 23:36:36 +00:00
|
|
|
gfx::FeatureStatus::Unavailable, "Failed to create new surface",
|
2022-04-18 18:11:08 +00:00
|
|
|
"FEATURE_FAILURE_WEBRENDER_NEW_SURFACE"_ns,
|
|
|
|
/* aCrashAfterFinalFallback */ true);
|
2021-04-14 12:51:16 +00:00
|
|
|
} else if (aError == wr::WebRenderError::BEGIN_DRAW) {
|
2022-05-20 17:02:55 +00:00
|
|
|
return gfxPlatform::FallbackFromAcceleration(
|
2021-04-14 12:51:16 +00:00
|
|
|
gfx::FeatureStatus::Unavailable, "BeginDraw() failed",
|
|
|
|
"FEATURE_FAILURE_WEBRENDER_BEGIN_DRAW"_ns);
|
2020-12-07 20:36:11 +00:00
|
|
|
} else if (aError == wr::WebRenderError::EXCESSIVE_RESETS) {
|
2022-05-20 17:02:55 +00:00
|
|
|
return gfxPlatform::FallbackFromAcceleration(
|
2021-01-14 19:59:10 +00:00
|
|
|
gfx::FeatureStatus::Unavailable, "Device resets exceeded threshold",
|
|
|
|
"FEATURE_FAILURE_WEBRENDER_EXCESSIVE_RESETS"_ns);
|
2017-08-30 00:10:22 +00:00
|
|
|
} else {
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Invalid value");
|
2022-05-20 17:02:55 +00:00
|
|
|
return gfxPlatform::FallbackFromAcceleration(
|
2021-02-01 23:36:36 +00:00
|
|
|
gfx::FeatureStatus::Unavailable, "Unhandled failure reason",
|
|
|
|
"FEATURE_FAILURE_WEBRENDER_UNHANDLED"_ns);
|
2017-08-30 00:10:22 +00:00
|
|
|
}
|
2022-05-20 17:02:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GPUProcessManager::DisableWebRenderConfig(wr::WebRenderError aError,
|
|
|
|
const nsCString& aMsg) {
|
|
|
|
// If we have a stable compositor process, this may just be due to an OOM or
|
|
|
|
// bad driver state. In that case, we should consider restarting the GPU
|
|
|
|
// process, or simulating a device reset to teardown the compositors to
|
|
|
|
// hopefully alleviate the situation.
|
|
|
|
if (IsProcessStable(TimeStamp::Now())) {
|
|
|
|
if (mProcess) {
|
|
|
|
mProcess->KillProcess();
|
|
|
|
} else {
|
|
|
|
SimulateDeviceReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
mLastError = Some(aError);
|
|
|
|
mLastErrorMsg = Some(aMsg);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mLastError.reset();
|
|
|
|
mLastErrorMsg.reset();
|
|
|
|
|
|
|
|
// Disable WebRender
|
|
|
|
bool wantRestart = FallbackFromAcceleration(aError, aMsg);
|
2020-09-09 01:04:53 +00:00
|
|
|
gfx::gfxVars::SetUseWebRenderDCompVideoOverlayWin(false);
|
Bug 1354411 - Rebuild CompositorSessions if WebRender is disabled r=kats
When WebRender creation is failed, WebRender is disabled in gecko. There is a case that WebRenderBridgeParents exist when WebRender is disabled. To handle this, gecko needs to rebuild all CompositorSessions.
There is also a problem related to gfxVars::UseWebRender on compositor thread. If e10s is enabled, but no-gpu process(default on linux and mac), gfxVars::UseWebRender change is soon notified by compositor thread tasks. If WebRender creation failure happens at 2nd WebRender creation, several WebRenderBridgeParents for 1st WebRender could exist. IPC messages from WebRenderLayerManager are normally async, then there is a chance that the WebRenderBridgeParents receive the messages after the gfxVars::UseWebRender change. Further the gfxVars::UseWebRender change in content process could be delayed than WebRenderBridgeParents, then content process does not have a way to stop sending PWebRenderBridge IPC until the change of gfxVars::UseWebRender is received. WebRenderBridgeParent related tasks handle the message, but some tasks are done based on gfxVars::UseWebRender. At this time, gfxVars::UseWebRender returned false on compositor thread, then it cause unexpected result for WebRenderBridgeParent and WebRender. To addres this inconsistent situation, WebRenderBridgeParent related tasks on compositor thread stop to use gfxVars::UseWebRender.
2017-08-04 05:36:41 +00:00
|
|
|
|
2021-02-01 23:36:36 +00:00
|
|
|
// If we still have the GPU process, and we fallback to a new configuration
|
|
|
|
// that prefers to have the GPU process, reset the counter.
|
|
|
|
if (wantRestart && mProcess) {
|
2021-05-06 19:47:38 +00:00
|
|
|
mUnstableProcessAttempts = 1;
|
2021-02-01 23:36:36 +00:00
|
|
|
}
|
|
|
|
|
2020-12-07 20:36:11 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::DisableWebRender(wr::WebRenderError aError,
|
|
|
|
const nsCString& aMsg) {
|
|
|
|
if (DisableWebRenderConfig(aError, aMsg)) {
|
|
|
|
if (mProcess) {
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
DestroyRemoteCompositorSessions();
|
2020-12-07 20:36:11 +00:00
|
|
|
} else {
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
DestroyInProcessCompositorSessions();
|
2020-12-07 20:36:11 +00:00
|
|
|
}
|
2021-02-01 23:36:36 +00:00
|
|
|
NotifyListenersOnCompositeDeviceReset();
|
Bug 1354411 - Rebuild CompositorSessions if WebRender is disabled r=kats
When WebRender creation is failed, WebRender is disabled in gecko. There is a case that WebRenderBridgeParents exist when WebRender is disabled. To handle this, gecko needs to rebuild all CompositorSessions.
There is also a problem related to gfxVars::UseWebRender on compositor thread. If e10s is enabled, but no-gpu process(default on linux and mac), gfxVars::UseWebRender change is soon notified by compositor thread tasks. If WebRender creation failure happens at 2nd WebRender creation, several WebRenderBridgeParents for 1st WebRender could exist. IPC messages from WebRenderLayerManager are normally async, then there is a chance that the WebRenderBridgeParents receive the messages after the gfxVars::UseWebRender change. Further the gfxVars::UseWebRender change in content process could be delayed than WebRenderBridgeParents, then content process does not have a way to stop sending PWebRenderBridge IPC until the change of gfxVars::UseWebRender is received. WebRenderBridgeParent related tasks handle the message, but some tasks are done based on gfxVars::UseWebRender. At this time, gfxVars::UseWebRender returned false on compositor thread, then it cause unexpected result for WebRenderBridgeParent and WebRender. To addres this inconsistent situation, WebRenderBridgeParent related tasks on compositor thread stop to use gfxVars::UseWebRender.
2017-08-04 05:36:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-30 00:10:22 +00:00
|
|
|
void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) {
|
2022-06-22 15:31:56 +00:00
|
|
|
gfxCriticalNote << "Handling webrender error " << (unsigned int)aError;
|
2020-09-09 01:04:53 +00:00
|
|
|
if (aError == wr::WebRenderError::VIDEO_OVERLAY) {
|
|
|
|
#ifdef XP_WIN
|
|
|
|
gfxVars::SetUseWebRenderDCompVideoOverlayWin(false);
|
|
|
|
#else
|
|
|
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2020-09-08 02:03:26 +00:00
|
|
|
DisableWebRender(aError, nsCString());
|
2017-08-30 00:10:22 +00:00
|
|
|
}
|
|
|
|
|
2020-12-10 14:26:32 +00:00
|
|
|
/* static */ void GPUProcessManager::RecordDeviceReset(
|
|
|
|
DeviceResetReason aReason) {
|
|
|
|
if (aReason != DeviceResetReason::FORCED_RESET) {
|
|
|
|
Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(aReason));
|
|
|
|
}
|
|
|
|
|
|
|
|
CrashReporter::AnnotateCrashReport(
|
|
|
|
CrashReporter::Annotation::DeviceResetReason, int(aReason));
|
|
|
|
}
|
|
|
|
|
2020-12-07 20:36:11 +00:00
|
|
|
bool GPUProcessManager::OnDeviceReset(bool aTrackThreshold) {
|
|
|
|
// Ignore resets for thresholding if requested.
|
|
|
|
if (!aTrackThreshold) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Detect whether the device is resetting too quickly or too much
|
|
|
|
// indicating that we should give up and use software
|
|
|
|
mDeviceResetCount++;
|
2019-07-09 06:37:45 +00:00
|
|
|
|
2016-11-10 02:57:04 +00:00
|
|
|
auto newTime = TimeStamp::Now();
|
|
|
|
auto delta = (int32_t)(newTime - mDeviceResetLastTime).ToMilliseconds();
|
|
|
|
mDeviceResetLastTime = newTime;
|
|
|
|
|
2020-12-07 20:36:11 +00:00
|
|
|
// Returns true if we should disable acceleration due to the reset.
|
|
|
|
return ShouldLimitDeviceResets(mDeviceResetCount, delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::OnInProcessDeviceReset(bool aTrackThreshold) {
|
|
|
|
if (OnDeviceReset(aTrackThreshold)) {
|
|
|
|
gfxCriticalNoteOnce << "In-process device reset threshold exceeded";
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
|
|
// FIXME(aosmond): Should we disable WebRender on other platforms?
|
|
|
|
DisableWebRenderConfig(wr::WebRenderError::EXCESSIVE_RESETS, nsCString());
|
|
|
|
#endif
|
|
|
|
}
|
2021-11-16 08:25:09 +00:00
|
|
|
#ifdef XP_WIN
|
|
|
|
// Ensure device reset handling before re-creating in process sessions.
|
|
|
|
// Normally nsWindow::OnPaint() already handled it.
|
|
|
|
gfxWindowsPlatform::GetPlatform()->HandleDeviceReset();
|
|
|
|
#endif
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
DestroyInProcessCompositorSessions();
|
2020-12-07 20:36:11 +00:00
|
|
|
NotifyListenersOnCompositeDeviceReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::OnRemoteProcessDeviceReset(GPUProcessHost* aHost) {
|
|
|
|
if (OnDeviceReset(/* aTrackThreshold */ true)) {
|
2016-11-10 02:57:04 +00:00
|
|
|
DestroyProcess();
|
|
|
|
DisableGPUProcess("GPU processed experienced too many device resets");
|
|
|
|
HandleProcessLost();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
DestroyRemoteCompositorSessions();
|
2017-06-15 18:34:00 +00:00
|
|
|
NotifyListenersOnCompositeDeviceReset();
|
|
|
|
}
|
2017-05-12 05:44:27 +00:00
|
|
|
|
2017-06-15 18:34:00 +00:00
|
|
|
void GPUProcessManager::NotifyListenersOnCompositeDeviceReset() {
|
2017-05-12 05:44:27 +00:00
|
|
|
for (const auto& listener : mListeners) {
|
|
|
|
listener->OnCompositorDeviceReset();
|
2016-11-06 19:01:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-11 02:37:03 +00:00
|
|
|
void GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost) {
|
|
|
|
MOZ_ASSERT(mProcess && mProcess == aHost);
|
|
|
|
|
2020-10-16 10:38:40 +00:00
|
|
|
if (StaticPrefs::layers_gpu_process_crash_also_crashes_browser()) {
|
|
|
|
MOZ_CRASH("GPU process crashed and pref is set to crash the browser.");
|
|
|
|
}
|
|
|
|
|
2017-09-26 17:21:52 +00:00
|
|
|
CompositorManagerChild::OnGPUProcessLost(aHost->GetProcessToken());
|
2021-12-08 19:08:17 +00:00
|
|
|
DestroyProcess(/* aUnexpectedShutdown */ true);
|
2016-09-20 08:16:03 +00:00
|
|
|
|
2021-05-06 19:47:38 +00:00
|
|
|
if (mUnstableProcessAttempts >
|
2019-06-27 04:48:58 +00:00
|
|
|
uint32_t(StaticPrefs::layers_gpu_process_max_restarts())) {
|
2016-11-11 22:51:25 +00:00
|
|
|
char disableMessage[64];
|
|
|
|
SprintfLiteral(disableMessage, "GPU process disabled after %d attempts",
|
2021-05-06 19:47:38 +00:00
|
|
|
mTotalProcessAttempts);
|
2021-02-01 23:36:36 +00:00
|
|
|
if (!MaybeDisableGPUProcess(disableMessage, /* aAllowRestart */ true)) {
|
|
|
|
// Fallback wants the GPU process. Reset our counter.
|
2021-05-06 19:47:38 +00:00
|
|
|
mUnstableProcessAttempts = 0;
|
2021-02-01 23:36:36 +00:00
|
|
|
HandleProcessLost();
|
|
|
|
}
|
2021-05-06 19:47:38 +00:00
|
|
|
} else if (mUnstableProcessAttempts >
|
2019-06-27 04:48:58 +00:00
|
|
|
uint32_t(StaticPrefs::
|
|
|
|
layers_gpu_process_max_restarts_with_decoder()) &&
|
2017-04-14 21:36:42 +00:00
|
|
|
mDecodeVideoOnGpuProcess) {
|
2017-04-14 21:34:01 +00:00
|
|
|
mDecodeVideoOnGpuProcess = false;
|
2017-04-14 21:36:42 +00:00
|
|
|
Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
|
|
|
|
uint32_t(FallbackType::DECODINGDISABLED));
|
2017-07-20 13:20:22 +00:00
|
|
|
HandleProcessLost();
|
2017-04-14 21:36:42 +00:00
|
|
|
} else {
|
|
|
|
Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
|
|
|
|
uint32_t(FallbackType::NONE));
|
2017-07-20 13:20:22 +00:00
|
|
|
HandleProcessLost();
|
2016-09-30 08:21:21 +00:00
|
|
|
}
|
2016-11-10 02:57:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::HandleProcessLost() {
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-09-30 08:21:21 +00:00
|
|
|
|
2016-09-20 08:18:50 +00:00
|
|
|
// The shutdown and restart sequence for the GPU process is as follows:
|
|
|
|
//
|
|
|
|
// (1) The GPU process dies. IPDL will enqueue an ActorDestroy message on
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// each channel owning a bridge to the GPU process, on the thread owning
|
|
|
|
// that channel.
|
2016-09-20 08:18:50 +00:00
|
|
|
//
|
|
|
|
// (2) The first channel to process its ActorDestroy message will post a
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// message to the main thread to call NotifyRemoteActorDestroyed on the
|
|
|
|
// GPUProcessManager, which calls OnProcessUnexpectedShutdown if it has
|
|
|
|
// not handled shutdown for this process yet. OnProcessUnexpectedShutdown
|
|
|
|
// is responsible for tearing down the old process and deciding whether
|
|
|
|
// or not to disable the GPU process. It then calls this function,
|
|
|
|
// HandleProcessLost.
|
2016-09-20 08:18:50 +00:00
|
|
|
//
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// (3) We then notify each widget that its session with the compositor is now
|
|
|
|
// invalid. The widget is responsible for destroying its layer manager
|
|
|
|
// and CompositorBridgeChild. Note that at this stage, not all actors may
|
|
|
|
// have received ActorDestroy yet. CompositorBridgeChild may attempt to
|
|
|
|
// send messages, and if this happens, it will probably report a
|
|
|
|
// MsgDropped error. This is okay.
|
2016-09-20 08:18:50 +00:00
|
|
|
//
|
|
|
|
// (4) At this point, the UI process has a clean slate: no layers should
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// exist for the old compositor. We may make a decision on whether or not
|
|
|
|
// to re-launch the GPU process. Or, on Android if the app is in the
|
|
|
|
// background we may decide to wait until it comes to the foreground
|
|
|
|
// before re-launching.
|
2016-09-20 08:18:50 +00:00
|
|
|
//
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// (5) When we do decide to re-launch, or continue without a GPU process, we
|
|
|
|
// notify each ContentParent of the lost connection. It will request new
|
|
|
|
// endpoints from the GPUProcessManager and forward them to its
|
|
|
|
// ContentChild. The parent-side of these endpoints may come from the
|
|
|
|
// compositor thread of the UI process, or the compositor thread of the
|
|
|
|
// GPU process. However, no actual compositors should exist yet.
|
2016-09-20 08:18:50 +00:00
|
|
|
//
|
|
|
|
// (6) Each ContentChild will receive new endpoints. It will destroy its
|
|
|
|
// Compositor/ImageBridgeChild singletons and recreate them, as well
|
|
|
|
// as invalidate all retained layers.
|
|
|
|
//
|
2019-04-09 22:39:01 +00:00
|
|
|
// (7) In addition, each ContentChild will ask each of its BrowserChildren
|
2016-09-20 08:18:50 +00:00
|
|
|
// to re-request association with the compositor for the window
|
|
|
|
// owning the tab. The sequence of calls looks like:
|
|
|
|
// (a) [CONTENT] ContentChild::RecvReinitRendering
|
2019-04-09 22:39:01 +00:00
|
|
|
// (b) [CONTENT] BrowserChild::ReinitRendering
|
|
|
|
// (c) [CONTENT] BrowserChild::SendEnsureLayersConnected
|
2019-04-09 21:38:15 +00:00
|
|
|
// (d) [UI] BrowserParent::RecvEnsureLayersConnected
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// (e) [UI] RemoteLayerTreeOwner::EnsureLayersConnected
|
2016-09-20 08:18:50 +00:00
|
|
|
// (f) [UI] CompositorBridgeChild::SendNotifyChildRecreated
|
|
|
|
//
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// Note that at step (e), RemoteLayerTreeOwner will call
|
|
|
|
// GetWindowRenderer on the nsIWidget owning the tab. This step ensures
|
|
|
|
// that a compositor exists for the window. If we decided to launch a new
|
|
|
|
// GPU Process, at this point we block until the process has launched and
|
|
|
|
// we're able to create a new window compositor. Otherwise, if
|
|
|
|
// compositing is now in-process, this will simply create a new
|
2016-09-20 08:18:50 +00:00
|
|
|
// CompositorBridgeParent in the UI process. If there are multiple tabs
|
|
|
|
// in the same window, additional tabs will simply return the already-
|
|
|
|
// established compositor.
|
|
|
|
//
|
|
|
|
// Finally, this step serves one other crucial function: tabs must be
|
|
|
|
// associated with a window compositor or else they can't forward
|
|
|
|
// layer transactions. So this step both ensures that a compositor
|
|
|
|
// exists, and that the tab can forward layers.
|
|
|
|
//
|
2017-06-15 18:34:00 +00:00
|
|
|
// (8) Last, if the window had no remote tabs, step (7) will not have
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// applied, and the window will not have a new compositor just yet. The
|
|
|
|
// next refresh tick and paint will ensure that one exists, again via
|
|
|
|
// nsIWidget::GetWindowRenderer. On Android, we called
|
|
|
|
// nsIWidgetListener::RequestRepaint back in step (3) to ensure this
|
|
|
|
// tick occurs, but on other platforms this is not necessary.
|
|
|
|
|
|
|
|
DestroyRemoteCompositorSessions();
|
2017-05-12 05:44:27 +00:00
|
|
|
|
Bug 1767128 - Rework and re-enable SurfaceControl rendering path on Android. r=agi,gfx-reviewers,aosmond
In bug 1762424 we introduced a rendering path on Android using the
SurfaceControl API, in order to work around a bug preventing recovery
from a GPU process crash. However, the initial implementation caused
this bug: repeatedly sending the same SurfaceControl objects over AIDL
to the GPU process resulted in them being leaked, eventually causing
severe display issues. Not only were we duplicating the SurfaceControl
for each widget, but each time a widget was resized too.
This patch reworks our usage of the SurfaceControl API to avoid ever
having to send them cross-process. Instead, we create a single child
SurfaceControl object for each SurfaceControl that is attached to a
widget. (Typically there will be a single one shared between all
widgets, changing only when the app is paused and resumed, which is
much fewer than one per widget per resize.)
In the parent process we obtain the Surfaces that will be rendered in
to from the child SurfaceControls, and only send those Surfaces to the
GPU process. Thankfully unlike SurfaceControls, sending Surfaces
cross-process does not cause leaks. When the GPU process dies we
simply destroy all of the child SurfaceControls, and recreate them
again on-demand.
Differential Revision: https://phabricator.services.mozilla.com/D147437
2022-05-31 18:41:07 +00:00
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
|
|
java::SurfaceControlManager::GetInstance()->OnGpuProcessLoss();
|
|
|
|
#endif
|
|
|
|
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// Re-launch the process if immediately if the GPU process is still enabled.
|
|
|
|
// Except on Android if the app is in the background, where we want to wait
|
|
|
|
// until the app is in the foreground again.
|
|
|
|
if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
|
|
|
|
if (mAppInForeground) {
|
2022-04-11 11:49:21 +00:00
|
|
|
Unused << LaunchGPUProcess();
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If the GPU process is disabled we can reinitialize rendering immediately.
|
|
|
|
// This will be handled in OnProcessLaunchComplete() if the GPU process is
|
|
|
|
// enabled.
|
|
|
|
ReinitializeRendering();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::ReinitializeRendering() {
|
2017-05-12 05:44:27 +00:00
|
|
|
// Notify content. This will ensure that each content process re-establishes
|
|
|
|
// a connection to the compositor thread (whether it's in-process or in a
|
|
|
|
// newly launched GPU process).
|
|
|
|
for (const auto& listener : mListeners) {
|
|
|
|
listener->OnCompositorUnexpectedShutdown();
|
|
|
|
}
|
2022-01-07 13:27:48 +00:00
|
|
|
|
|
|
|
// Notify any observers that the compositor has been reinitialized,
|
|
|
|
// eg the ZoomConstraintsClients for parent process documents.
|
|
|
|
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
|
|
|
if (observerService) {
|
|
|
|
observerService->NotifyObservers(nullptr, "compositor-reinitialized",
|
|
|
|
nullptr);
|
|
|
|
}
|
2017-05-12 05:44:27 +00:00
|
|
|
}
|
2016-09-20 08:18:50 +00:00
|
|
|
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
void GPUProcessManager::DestroyRemoteCompositorSessions() {
|
2016-09-20 08:16:03 +00:00
|
|
|
// Build a list of sessions to notify, since notification might delete
|
|
|
|
// entries from the list.
|
|
|
|
nsTArray<RefPtr<RemoteCompositorSession>> sessions;
|
|
|
|
for (auto& session : mRemoteSessions) {
|
|
|
|
sessions.AppendElement(session);
|
|
|
|
}
|
|
|
|
|
2016-09-20 08:18:50 +00:00
|
|
|
// Notify each widget that we have lost the GPU process. This will ensure
|
|
|
|
// that each widget destroys its layer manager and CompositorBridgeChild.
|
2016-09-20 08:16:03 +00:00
|
|
|
for (const auto& session : sessions) {
|
|
|
|
session->NotifySessionLost();
|
|
|
|
}
|
2016-06-11 02:37:03 +00:00
|
|
|
}
|
|
|
|
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
void GPUProcessManager::DestroyInProcessCompositorSessions() {
|
2017-06-15 18:34:00 +00:00
|
|
|
// Build a list of sessions to notify, since notification might delete
|
|
|
|
// entries from the list.
|
|
|
|
nsTArray<RefPtr<InProcessCompositorSession>> sessions;
|
|
|
|
for (auto& session : mInProcessSessions) {
|
|
|
|
sessions.AppendElement(session);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify each widget that we have lost the GPU process. This will ensure
|
|
|
|
// that each widget destroys its layer manager and CompositorBridgeChild.
|
|
|
|
for (const auto& session : sessions) {
|
|
|
|
session->NotifySessionLost();
|
|
|
|
}
|
2022-05-20 17:02:55 +00:00
|
|
|
|
|
|
|
// Ensure our stablility state is reset so that we don't necessarily crash
|
|
|
|
// right away on some WebRender errors.
|
|
|
|
CompositorBridgeParent::ResetStable();
|
|
|
|
ResetProcessStable();
|
2017-06-15 18:34:00 +00:00
|
|
|
}
|
|
|
|
|
2016-07-18 04:24:28 +00:00
|
|
|
void GPUProcessManager::NotifyRemoteActorDestroyed(
|
|
|
|
const uint64_t& aProcessToken) {
|
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod(
|
|
|
|
&GPUProcessManager::NotifyRemoteActorDestroyed, aProcessToken);
|
|
|
|
NS_DispatchToMainThread(task.forget());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mProcessToken != aProcessToken) {
|
|
|
|
// This token is for an older process; we can safely ignore it.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// One of the bridged top-level actors for the GPU process has been
|
|
|
|
// prematurely terminated, and we're receiving a notification. This
|
|
|
|
// can happen if the ActorDestroy for a bridged protocol fires
|
|
|
|
// before the ActorDestroy for PGPUChild.
|
2016-09-20 08:16:03 +00:00
|
|
|
OnProcessUnexpectedShutdown(mProcess);
|
2016-07-18 04:24:28 +00:00
|
|
|
}
|
|
|
|
|
2016-07-19 18:56:06 +00:00
|
|
|
void GPUProcessManager::CleanShutdown() {
|
|
|
|
DestroyProcess();
|
2016-10-07 07:07:10 +00:00
|
|
|
mVsyncIOThread = nullptr;
|
2016-07-19 18:56:06 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 19:44:40 +00:00
|
|
|
void GPUProcessManager::KillProcess() {
|
|
|
|
if (!mProcess) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mProcess->KillProcess();
|
|
|
|
}
|
|
|
|
|
2021-12-08 19:08:17 +00:00
|
|
|
void GPUProcessManager::CrashProcess() {
|
|
|
|
if (!mProcess) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mProcess->CrashProcess();
|
|
|
|
}
|
|
|
|
|
2021-12-08 19:08:17 +00:00
|
|
|
void GPUProcessManager::DestroyProcess(bool aUnexpectedShutdown) {
|
2016-06-11 02:27:24 +00:00
|
|
|
if (!mProcess) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-08 19:08:17 +00:00
|
|
|
mProcess->Shutdown(aUnexpectedShutdown);
|
2016-07-18 04:24:28 +00:00
|
|
|
mProcessToken = 0;
|
2016-06-11 02:27:24 +00:00
|
|
|
mProcess = nullptr;
|
|
|
|
mGPUChild = nullptr;
|
2020-02-18 15:57:14 +00:00
|
|
|
mQueuedPrefs.Clear();
|
2016-11-02 23:45:38 +00:00
|
|
|
if (mVsyncBridge) {
|
|
|
|
mVsyncBridge->Close();
|
|
|
|
mVsyncBridge = nullptr;
|
|
|
|
}
|
2017-04-03 22:11:27 +00:00
|
|
|
|
|
|
|
CrashReporter::AnnotateCrashReport(
|
Bug 1348273 - Convert crash annotations into a machine-readable list of constants; r=ted.mielczarek,njn,dholbert,mak,cpearce,mcmanus,froydnj,Dexter,jrmuizel,jchen,jimm,bz,surkov
This introduces the machinery needed to generate crash annotations from a YAML
file. The relevant C++ functions are updated to take a typed enum. JavaScript
calls are unaffected but they will throw if the string argument does not
correspond to one of the known entries in the C++ enum. The existing whitelists
and blacklists of annotations are also generated from the YAML file and all
duplicate code related to them has been consolidated. Once written out to the
.extra file the annotations are converted in string form and are no different
than the existing ones.
All existing annotations have been included in the list (and some obsolete ones
have been removed) and all call sites have been updated including tests where
appropriate.
--HG--
extra : source : 4f6c43f2830701ec5552e08e3f1b06fe6d045860
2018-07-05 13:42:11 +00:00
|
|
|
CrashReporter::Annotation::GPUProcessStatus, "Destroyed"_ns);
|
2016-05-23 07:27:01 +00:00
|
|
|
}
|
|
|
|
|
2016-07-19 18:56:07 +00:00
|
|
|
already_AddRefed<CompositorSession> GPUProcessManager::CreateTopLevelCompositor(
|
2021-09-05 22:36:45 +00:00
|
|
|
nsBaseWidget* aWidget, WebRenderLayerManager* aLayerManager,
|
2017-01-12 22:29:41 +00:00
|
|
|
CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
|
2017-07-20 13:20:22 +00:00
|
|
|
bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize,
|
2022-03-11 07:49:04 +00:00
|
|
|
uint64_t aInnerWindowId, bool* aRetryOut) {
|
2017-07-20 13:20:22 +00:00
|
|
|
MOZ_ASSERT(aRetryOut);
|
|
|
|
|
2018-03-24 23:06:01 +00:00
|
|
|
LayersId layerTreeId = AllocateLayerTreeId();
|
2016-07-18 04:24:27 +00:00
|
|
|
|
2017-06-28 18:31:42 +00:00
|
|
|
EnsureProtocolsReady();
|
2017-04-05 22:42:50 +00:00
|
|
|
|
|
|
|
RefPtr<CompositorSession> session;
|
2016-07-20 07:17:28 +00:00
|
|
|
|
2017-03-30 01:23:24 +00:00
|
|
|
if (EnsureGPUReady()) {
|
2022-03-11 07:49:04 +00:00
|
|
|
session = CreateRemoteSession(aWidget, aLayerManager, layerTreeId, aScale,
|
|
|
|
aOptions, aUseExternalSurfaceSize,
|
|
|
|
aSurfaceSize, aInnerWindowId);
|
2017-04-05 22:42:50 +00:00
|
|
|
if (!session) {
|
|
|
|
// We couldn't create a remote compositor, so abort the process.
|
|
|
|
DisableGPUProcess("Failed to create remote compositor");
|
2017-07-20 13:20:22 +00:00
|
|
|
*aRetryOut = true;
|
|
|
|
return nullptr;
|
2016-07-18 04:24:28 +00:00
|
|
|
}
|
2017-07-20 13:20:22 +00:00
|
|
|
} else {
|
2017-04-05 22:42:50 +00:00
|
|
|
session = InProcessCompositorSession::Create(
|
|
|
|
aWidget, aLayerManager, layerTreeId, aScale, aOptions,
|
2022-03-11 07:49:04 +00:00
|
|
|
aUseExternalSurfaceSize, aSurfaceSize, AllocateNamespace(),
|
|
|
|
aInnerWindowId);
|
2016-07-18 04:24:28 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 22:42:50 +00:00
|
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
|
|
|
if (session) {
|
|
|
|
// Nothing to do if controller gets a nullptr
|
|
|
|
RefPtr<UiCompositorControllerChild> controller =
|
|
|
|
CreateUiCompositorController(aWidget, session->RootLayerTreeId());
|
|
|
|
session->SetUiCompositorControllerChild(controller);
|
|
|
|
}
|
|
|
|
#endif // defined(MOZ_WIDGET_ANDROID)
|
|
|
|
|
2017-07-20 13:20:22 +00:00
|
|
|
*aRetryOut = false;
|
|
|
|
return session.forget();
|
2016-05-23 07:27:01 +00:00
|
|
|
}
|
|
|
|
|
2016-07-19 18:56:07 +00:00
|
|
|
RefPtr<CompositorSession> GPUProcessManager::CreateRemoteSession(
|
2021-09-05 22:36:45 +00:00
|
|
|
nsBaseWidget* aWidget, WebRenderLayerManager* aLayerManager,
|
2018-03-24 23:06:01 +00:00
|
|
|
const LayersId& aRootLayerTreeId, CSSToLayoutDeviceScale aScale,
|
2017-01-12 22:29:41 +00:00
|
|
|
const CompositorOptions& aOptions, bool aUseExternalSurfaceSize,
|
2022-03-11 07:49:04 +00:00
|
|
|
const gfx::IntSize& aSurfaceSize, uint64_t aInnerWindowId) {
|
2016-07-18 04:24:28 +00:00
|
|
|
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
|
2020-04-05 03:50:33 +00:00
|
|
|
widget::CompositorWidgetInitData initData;
|
2017-06-13 19:45:03 +00:00
|
|
|
aWidget->GetCompositorWidgetInitData(&initData);
|
|
|
|
|
2017-06-14 15:39:59 +00:00
|
|
|
RefPtr<CompositorBridgeChild> child =
|
|
|
|
CompositorManagerChild::CreateWidgetCompositorBridge(
|
|
|
|
mProcessToken, aLayerManager, AllocateNamespace(), aScale, aOptions,
|
2022-03-11 07:49:04 +00:00
|
|
|
aUseExternalSurfaceSize, aSurfaceSize, aInnerWindowId);
|
2017-06-14 15:39:59 +00:00
|
|
|
if (!child) {
|
|
|
|
gfxCriticalNote << "Failed to create CompositorBridgeChild";
|
2017-06-13 19:45:03 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-07-19 18:56:07 +00:00
|
|
|
RefPtr<CompositorVsyncDispatcher> dispatcher =
|
|
|
|
aWidget->GetCompositorVsyncDispatcher();
|
2020-04-05 03:50:33 +00:00
|
|
|
RefPtr<widget::CompositorWidgetVsyncObserver> observer =
|
|
|
|
new widget::CompositorWidgetVsyncObserver(mVsyncBridge, aRootLayerTreeId);
|
2016-07-19 18:56:07 +00:00
|
|
|
|
2020-04-05 03:50:33 +00:00
|
|
|
widget::CompositorWidgetChild* widget =
|
|
|
|
new widget::CompositorWidgetChild(dispatcher, observer, initData);
|
2016-07-20 07:19:27 +00:00
|
|
|
if (!child->SendPCompositorWidgetConstructor(widget, initData)) {
|
2016-07-18 04:24:28 +00:00
|
|
|
return nullptr;
|
2016-07-20 07:19:27 +00:00
|
|
|
}
|
2020-01-08 18:37:38 +00:00
|
|
|
if (!widget->Initialize()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2016-07-20 07:19:27 +00:00
|
|
|
if (!child->SendInitialize(aRootLayerTreeId)) {
|
2016-07-18 04:24:28 +00:00
|
|
|
return nullptr;
|
2016-07-20 07:19:27 +00:00
|
|
|
}
|
2016-07-18 04:24:28 +00:00
|
|
|
|
2016-08-29 13:18:00 +00:00
|
|
|
RefPtr<APZCTreeManagerChild> apz = nullptr;
|
2017-01-12 22:29:41 +00:00
|
|
|
if (aOptions.UseAPZ()) {
|
2018-03-24 23:06:01 +00:00
|
|
|
PAPZCTreeManagerChild* papz =
|
|
|
|
child->SendPAPZCTreeManagerConstructor(LayersId{0});
|
2016-08-29 13:18:00 +00:00
|
|
|
if (!papz) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
apz = static_cast<APZCTreeManagerChild*>(papz);
|
2018-03-16 20:28:19 +00:00
|
|
|
|
Bug 1340301 - Ensure APZ functions are called from correct threads on Android with GPU process. r=botond
On Android the APZ controller thread is the android UI thread, rather
than the Gecko main thread as on other platforms. There some places
where the main thread requires to call IAPZCTreeManager functions that
must run on the controller thread. Currently we use the function
DispatchToControllerThread() prior to calling various IAPZCTreeManager
APIs to achieve this.
This works just fine for now, as there is no GPU process on
Android. However, once we do add a GPU process we will encounter
issues:
Firstly, there will now be a cross-process APZInputBridge rather than
using an in-process APZCTreeManager. The PAPZInputBridge protocol is
managed by PGPU, and therefore must run on the main thread in the
parent process. The input we require to send over the bridge, however,
originates from the UI thread.
To solve this we can convert PAPZInputBridge to a top-level protocol,
and bind it to the UI thread on Android. We can then send input
directly from the UI thread without issues.
Secondly, the PAPZCTreeManager protocol must also run from the main
thread in the parent process, as it is managed by
PCompositorBridge. Unlike PAPZInputBridge we cannot convert
PAPZCTreeManager in to a top level protocol, as it relies on the
ordering guarantees with PCompositorBridge.
We must therefore ensure that we only dispatch IAPZCTreeManager calls
to the controller thread when using an in-process
APZCTreeManager. Out-of-process calls, on the other hand, must be
dispatched to the main thread where we can send IPDL commands from. To
do this, we move the dispatch logic away from the callsites of
IAPZCTreeManager APIs, and in to the APZCTreeManager and
APZCTreeManagerChild implementations themselves.
Differential Revision: https://phabricator.services.mozilla.com/D131120
2021-11-20 09:49:14 +00:00
|
|
|
ipc::Endpoint<PAPZInputBridgeParent> parentPipe;
|
|
|
|
ipc::Endpoint<PAPZInputBridgeChild> childPipe;
|
|
|
|
nsresult rv = PAPZInputBridge::CreateEndpoints(mGPUChild->OtherPid(),
|
|
|
|
base::GetCurrentProcId(),
|
|
|
|
&parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
2018-03-16 20:28:19 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
Bug 1340301 - Ensure APZ functions are called from correct threads on Android with GPU process. r=botond
On Android the APZ controller thread is the android UI thread, rather
than the Gecko main thread as on other platforms. There some places
where the main thread requires to call IAPZCTreeManager functions that
must run on the controller thread. Currently we use the function
DispatchToControllerThread() prior to calling various IAPZCTreeManager
APIs to achieve this.
This works just fine for now, as there is no GPU process on
Android. However, once we do add a GPU process we will encounter
issues:
Firstly, there will now be a cross-process APZInputBridge rather than
using an in-process APZCTreeManager. The PAPZInputBridge protocol is
managed by PGPU, and therefore must run on the main thread in the
parent process. The input we require to send over the bridge, however,
originates from the UI thread.
To solve this we can convert PAPZInputBridge to a top-level protocol,
and bind it to the UI thread on Android. We can then send input
directly from the UI thread without issues.
Secondly, the PAPZCTreeManager protocol must also run from the main
thread in the parent process, as it is managed by
PCompositorBridge. Unlike PAPZInputBridge we cannot convert
PAPZCTreeManager in to a top level protocol, as it relies on the
ordering guarantees with PCompositorBridge.
We must therefore ensure that we only dispatch IAPZCTreeManager calls
to the controller thread when using an in-process
APZCTreeManager. Out-of-process calls, on the other hand, must be
dispatched to the main thread where we can send IPDL commands from. To
do this, we move the dispatch logic away from the callsites of
IAPZCTreeManager APIs, and in to the APZCTreeManager and
APZCTreeManagerChild implementations themselves.
Differential Revision: https://phabricator.services.mozilla.com/D131120
2021-11-20 09:49:14 +00:00
|
|
|
mGPUChild->SendInitAPZInputBridge(aRootLayerTreeId, std::move(parentPipe));
|
|
|
|
|
|
|
|
RefPtr<APZInputBridgeChild> inputBridge =
|
|
|
|
APZInputBridgeChild::Create(mProcessToken, std::move(childPipe));
|
|
|
|
if (!inputBridge) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
apz->SetInputBridge(inputBridge);
|
2016-08-29 13:18:00 +00:00
|
|
|
}
|
|
|
|
|
2020-02-13 14:38:48 +00:00
|
|
|
return new RemoteCompositorSession(aWidget, child, widget, apz,
|
|
|
|
aRootLayerTreeId);
|
2016-07-18 04:24:28 +00:00
|
|
|
#else
|
|
|
|
gfxCriticalNote << "Platform does not support out-of-process compositing";
|
|
|
|
return nullptr;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-09-20 08:15:49 +00:00
|
|
|
bool GPUProcessManager::CreateContentBridges(
|
|
|
|
base::ProcessId aOtherProcess,
|
2017-06-14 15:39:59 +00:00
|
|
|
ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
|
2016-09-20 08:15:49 +00:00
|
|
|
ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
|
2016-11-08 02:21:35 +00:00
|
|
|
ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
|
2019-06-11 02:01:34 +00:00
|
|
|
ipc::Endpoint<PRemoteDecoderManagerChild>* aOutVideoManager,
|
2017-04-14 08:06:09 +00:00
|
|
|
nsTArray<uint32_t>* aNamespaces) {
|
2017-06-14 15:39:59 +00:00
|
|
|
if (!CreateContentCompositorManager(aOtherProcess, aOutCompositor) ||
|
2016-09-20 08:15:49 +00:00
|
|
|
!CreateContentImageBridge(aOtherProcess, aOutImageBridge) ||
|
|
|
|
!CreateContentVRManager(aOtherProcess, aOutVRBridge)) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-11-08 02:21:35 +00:00
|
|
|
// VideoDeocderManager is only supported in the GPU process, so we allow this
|
|
|
|
// to be fallible.
|
2019-06-11 02:01:34 +00:00
|
|
|
CreateContentRemoteDecoderManager(aOtherProcess, aOutVideoManager);
|
2017-06-14 15:39:59 +00:00
|
|
|
// Allocates 3 namespaces(for CompositorManagerChild, CompositorBridgeChild
|
|
|
|
// and ImageBridgeChild)
|
|
|
|
aNamespaces->AppendElement(AllocateNamespace());
|
2017-04-14 08:06:09 +00:00
|
|
|
aNamespaces->AppendElement(AllocateNamespace());
|
|
|
|
aNamespaces->AppendElement(AllocateNamespace());
|
2016-09-20 08:15:49 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-14 15:39:59 +00:00
|
|
|
bool GPUProcessManager::CreateContentCompositorManager(
|
|
|
|
base::ProcessId aOtherProcess,
|
|
|
|
ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint) {
|
|
|
|
ipc::Endpoint<PCompositorManagerParent> parentPipe;
|
|
|
|
ipc::Endpoint<PCompositorManagerChild> childPipe;
|
2016-07-18 04:24:28 +00:00
|
|
|
|
2017-06-29 18:35:45 +00:00
|
|
|
base::ProcessId parentPid =
|
|
|
|
EnsureGPUReady() ? mGPUChild->OtherPid() : base::GetCurrentProcId();
|
2016-07-18 04:24:28 +00:00
|
|
|
|
2017-06-14 15:39:59 +00:00
|
|
|
nsresult rv = PCompositorManager::CreateEndpoints(parentPid, aOtherProcess,
|
2016-07-18 04:24:28 +00:00
|
|
|
&parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
2017-06-14 15:39:59 +00:00
|
|
|
gfxCriticalNote << "Could not create content compositor manager: "
|
|
|
|
<< hexa(int(rv));
|
2016-07-18 04:24:28 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-06-29 18:35:45 +00:00
|
|
|
if (mGPUChild) {
|
2018-05-30 19:15:35 +00:00
|
|
|
mGPUChild->SendNewContentCompositorManager(std::move(parentPipe));
|
2019-04-23 12:21:56 +00:00
|
|
|
} else if (!CompositorManagerParent::Create(std::move(parentPipe),
|
|
|
|
/* aIsRoot */ false)) {
|
2019-03-12 19:08:01 +00:00
|
|
|
return false;
|
2016-07-18 04:24:28 +00:00
|
|
|
}
|
2016-07-18 04:24:28 +00:00
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
*aOutEndpoint = std::move(childPipe);
|
2016-07-18 04:24:28 +00:00
|
|
|
return true;
|
2016-05-23 07:28:51 +00:00
|
|
|
}
|
|
|
|
|
2016-07-20 07:18:30 +00:00
|
|
|
bool GPUProcessManager::CreateContentImageBridge(
|
|
|
|
base::ProcessId aOtherProcess,
|
|
|
|
ipc::Endpoint<PImageBridgeChild>* aOutEndpoint) {
|
|
|
|
EnsureImageBridgeChild();
|
|
|
|
|
2017-06-29 18:35:45 +00:00
|
|
|
base::ProcessId parentPid =
|
|
|
|
EnsureGPUReady() ? mGPUChild->OtherPid() : base::GetCurrentProcId();
|
2016-07-20 07:18:30 +00:00
|
|
|
|
|
|
|
ipc::Endpoint<PImageBridgeParent> parentPipe;
|
|
|
|
ipc::Endpoint<PImageBridgeChild> childPipe;
|
|
|
|
nsresult rv = PImageBridge::CreateEndpoints(parentPid, aOtherProcess,
|
|
|
|
&parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
gfxCriticalNote << "Could not create content compositor bridge: "
|
|
|
|
<< hexa(int(rv));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-06-29 18:35:45 +00:00
|
|
|
if (mGPUChild) {
|
2018-05-30 19:15:35 +00:00
|
|
|
mGPUChild->SendNewContentImageBridge(std::move(parentPipe));
|
2016-07-20 07:19:27 +00:00
|
|
|
} else {
|
2018-05-30 19:15:35 +00:00
|
|
|
if (!ImageBridgeParent::CreateForContent(std::move(parentPipe))) {
|
2016-07-20 07:19:27 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2016-07-20 07:18:30 +00:00
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
*aOutEndpoint = std::move(childPipe);
|
2016-07-20 07:18:30 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-31 19:44:40 +00:00
|
|
|
base::ProcessId GPUProcessManager::GPUProcessPid() {
|
Bug 1766377 - Fix some sign-compare warnings by using ProcessId more consistently. r=nika,necko-reviewers,kershaw
dom/media/ipc/RDDProcessManager.cpp(320,21): error: comparison of integers of different signs: 'base::ProcessId' (aka 'unsigned long') and 'int' [-Werror,-Wsign-compare]
gpuProcessPid != -1 ? gpuProcessPid : base::GetCurrentProcId();
~~~~~~~~~~~~~ ^ ~~
dom/media/ipc/RDDProcessManager.cpp(332,21): error: comparison of integers of different signs: 'base::ProcessId' (aka 'unsigned long') and 'int' [-Werror,-Wsign-compare]
if (gpuProcessPid != -1) {
~~~~~~~~~~~~~ ^ ~~
gfx/layers/ipc/SharedSurfacesParent.cpp(360,38): error: comparison of integers of different signs: 'base::ProcessId' (aka 'unsigned long') and 'int' [-Werror,-Wsign-compare]
if (!gpm || gpm->GPUProcessPid() != -1) {
~~~~~~~~~~~~~~~~~~~~ ^ ~~
ipc/glue/MessageChannel.cpp(2145,13): error: comparison of integers of different signs: 'int32_t' (aka 'int') and 'const base::ProcessId' (aka 'const unsigned long') [-Werror,-Wsign-compare]
if (pid != base::kInvalidProcessId &&
~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~
Differential Revision: https://phabricator.services.mozilla.com/D144688
2022-04-27 07:45:19 +00:00
|
|
|
base::ProcessId gpuPid =
|
|
|
|
mGPUChild ? mGPUChild->OtherPid() : base::kInvalidProcessId;
|
2016-10-31 19:44:40 +00:00
|
|
|
return gpuPid;
|
|
|
|
}
|
|
|
|
|
2016-07-21 07:14:59 +00:00
|
|
|
bool GPUProcessManager::CreateContentVRManager(
|
|
|
|
base::ProcessId aOtherProcess,
|
|
|
|
ipc::Endpoint<PVRManagerChild>* aOutEndpoint) {
|
2016-07-21 07:14:59 +00:00
|
|
|
EnsureVRManager();
|
|
|
|
|
2017-06-29 18:35:45 +00:00
|
|
|
base::ProcessId parentPid =
|
|
|
|
EnsureGPUReady() ? mGPUChild->OtherPid() : base::GetCurrentProcId();
|
2016-07-21 07:14:59 +00:00
|
|
|
|
|
|
|
ipc::Endpoint<PVRManagerParent> parentPipe;
|
|
|
|
ipc::Endpoint<PVRManagerChild> childPipe;
|
|
|
|
nsresult rv = PVRManager::CreateEndpoints(parentPid, aOtherProcess,
|
|
|
|
&parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
gfxCriticalNote << "Could not create content compositor bridge: "
|
|
|
|
<< hexa(int(rv));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-06-29 18:35:45 +00:00
|
|
|
if (mGPUChild) {
|
2018-05-30 19:15:35 +00:00
|
|
|
mGPUChild->SendNewContentVRManager(std::move(parentPipe));
|
2016-07-21 07:14:59 +00:00
|
|
|
} else {
|
2018-05-30 19:15:35 +00:00
|
|
|
if (!VRManagerParent::CreateForContent(std::move(parentPipe))) {
|
2016-07-21 07:14:59 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-07-21 07:14:59 +00:00
|
|
|
}
|
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
*aOutEndpoint = std::move(childPipe);
|
2016-07-21 07:14:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-11 02:01:34 +00:00
|
|
|
void GPUProcessManager::CreateContentRemoteDecoderManager(
|
2016-09-21 09:25:33 +00:00
|
|
|
base::ProcessId aOtherProcess,
|
2019-06-11 02:01:34 +00:00
|
|
|
ipc::Endpoint<PRemoteDecoderManagerChild>* aOutEndpoint) {
|
2019-06-28 04:09:05 +00:00
|
|
|
if (!EnsureGPUReady() || !StaticPrefs::media_gpu_process_decoder() ||
|
2017-04-14 21:34:01 +00:00
|
|
|
!mDecodeVideoOnGpuProcess) {
|
2016-11-08 02:21:35 +00:00
|
|
|
return;
|
2016-09-21 09:25:33 +00:00
|
|
|
}
|
|
|
|
|
2019-06-11 02:01:34 +00:00
|
|
|
ipc::Endpoint<PRemoteDecoderManagerParent> parentPipe;
|
|
|
|
ipc::Endpoint<PRemoteDecoderManagerChild> childPipe;
|
2016-09-21 09:25:33 +00:00
|
|
|
|
2019-06-11 02:01:34 +00:00
|
|
|
nsresult rv = PRemoteDecoderManager::CreateEndpoints(
|
2016-09-21 09:25:33 +00:00
|
|
|
mGPUChild->OtherPid(), aOtherProcess, &parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
gfxCriticalNote << "Could not create content video decoder: "
|
|
|
|
<< hexa(int(rv));
|
2016-11-08 02:21:35 +00:00
|
|
|
return;
|
2016-09-21 09:25:33 +00:00
|
|
|
}
|
|
|
|
|
2019-06-11 02:01:34 +00:00
|
|
|
mGPUChild->SendNewContentRemoteDecoderManager(std::move(parentPipe));
|
2016-09-21 09:25:33 +00:00
|
|
|
|
2018-05-30 19:15:35 +00:00
|
|
|
*aOutEndpoint = std::move(childPipe);
|
2016-09-21 09:25:33 +00:00
|
|
|
}
|
|
|
|
|
2019-11-04 03:41:57 +00:00
|
|
|
void GPUProcessManager::InitVideoBridge(
|
2022-09-03 00:53:59 +00:00
|
|
|
ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge,
|
|
|
|
layers::VideoBridgeSource aSource) {
|
2019-11-04 03:41:57 +00:00
|
|
|
if (EnsureGPUReady()) {
|
2022-09-03 00:53:59 +00:00
|
|
|
mGPUChild->SendInitVideoBridge(std::move(aVideoBridge), aSource);
|
2019-11-04 03:41:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-24 23:06:01 +00:00
|
|
|
void GPUProcessManager::MapLayerTreeId(LayersId aLayersId,
|
|
|
|
base::ProcessId aOwningId) {
|
2017-03-30 01:23:24 +00:00
|
|
|
if (EnsureGPUReady()) {
|
2017-04-03 22:13:38 +00:00
|
|
|
mGPUChild->SendAddLayerTreeIdMapping(
|
|
|
|
LayerTreeIdMapping(aLayersId, aOwningId));
|
2016-11-02 20:55:07 +00:00
|
|
|
}
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
|
|
|
|
// Must do this *after* the call to EnsureGPUReady, so that if the
|
|
|
|
// process is launched as a result then it is initialized without this
|
|
|
|
// LayersId, meaning it can be successfully mapped.
|
|
|
|
LayerTreeOwnerTracker::Get()->Map(aLayersId, aOwningId);
|
2016-11-02 20:55:07 +00:00
|
|
|
}
|
|
|
|
|
2018-03-24 23:06:01 +00:00
|
|
|
void GPUProcessManager::UnmapLayerTreeId(LayersId aLayersId,
|
|
|
|
base::ProcessId aOwningId) {
|
2017-03-30 01:23:24 +00:00
|
|
|
if (EnsureGPUReady()) {
|
2016-11-02 20:55:07 +00:00
|
|
|
mGPUChild->SendRemoveLayerTreeIdMapping(
|
|
|
|
LayerTreeIdMapping(aLayersId, aOwningId));
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
} else {
|
|
|
|
CompositorBridgeParent::DeallocateLayerTreeId(aLayersId);
|
2016-08-16 20:59:13 +00:00
|
|
|
}
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
|
|
|
|
// Must do this *after* the call to EnsureGPUReady, so that if the
|
|
|
|
// process is launched as a result then it is initialized with this
|
|
|
|
// LayersId, meaning it can be successfully unmapped.
|
|
|
|
LayerTreeOwnerTracker::Get()->Unmap(aLayersId, aOwningId);
|
2016-08-16 20:59:13 +00:00
|
|
|
}
|
|
|
|
|
2018-03-24 23:06:01 +00:00
|
|
|
bool GPUProcessManager::IsLayerTreeIdMapped(LayersId aLayersId,
|
|
|
|
base::ProcessId aRequestingId) {
|
2016-08-16 20:59:13 +00:00
|
|
|
return LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, aRequestingId);
|
|
|
|
}
|
|
|
|
|
2016-05-23 07:27:57 +00:00
|
|
|
LayersId GPUProcessManager::AllocateLayerTreeId() {
|
2017-05-30 00:59:44 +00:00
|
|
|
// Allocate tree id by using id namespace.
|
|
|
|
// By it, tree id does not conflict with external image id and
|
|
|
|
// async image pipeline id.
|
2016-07-18 04:24:27 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-05-30 00:59:44 +00:00
|
|
|
++mResourceId;
|
|
|
|
if (mResourceId == UINT32_MAX) {
|
|
|
|
// Move to next id namespace.
|
|
|
|
mIdNamespace = AllocateNamespace();
|
|
|
|
mResourceId = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t layerTreeId = mIdNamespace;
|
|
|
|
layerTreeId = (layerTreeId << 32) | mResourceId;
|
2018-03-24 23:06:01 +00:00
|
|
|
return LayersId{layerTreeId};
|
2016-05-23 07:27:57 +00:00
|
|
|
}
|
|
|
|
|
2017-04-14 08:06:09 +00:00
|
|
|
uint32_t GPUProcessManager::AllocateNamespace() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return ++mNextNamespace;
|
|
|
|
}
|
|
|
|
|
2017-04-03 22:13:37 +00:00
|
|
|
bool GPUProcessManager::AllocateAndConnectLayerTreeId(
|
|
|
|
PCompositorBridgeChild* aCompositorBridge, base::ProcessId aOtherPid,
|
2017-04-09 21:30:27 +00:00
|
|
|
LayersId* aOutLayersId, CompositorOptions* aOutCompositorOptions) {
|
2018-03-24 23:06:01 +00:00
|
|
|
LayersId layersId = AllocateLayerTreeId();
|
2017-04-03 22:13:37 +00:00
|
|
|
*aOutLayersId = layersId;
|
|
|
|
|
|
|
|
if (!mGPUChild || !aCompositorBridge) {
|
|
|
|
// If we're not remoting to another process, or there is no compositor,
|
|
|
|
// then we'll send at most one message. In this case we can just keep
|
|
|
|
// the old behavior of making sure the mapping occurs, and maybe sending
|
|
|
|
// a creation notification.
|
|
|
|
MapLayerTreeId(layersId, aOtherPid);
|
|
|
|
if (!aCompositorBridge) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-09 21:30:27 +00:00
|
|
|
return aCompositorBridge->SendNotifyChildCreated(layersId,
|
|
|
|
aOutCompositorOptions);
|
2017-04-03 22:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Use the combined message path.
|
|
|
|
LayerTreeOwnerTracker::Get()->Map(layersId, aOtherPid);
|
2017-04-09 21:30:27 +00:00
|
|
|
return aCompositorBridge->SendMapAndNotifyChildCreated(layersId, aOtherPid,
|
|
|
|
aOutCompositorOptions);
|
2017-04-03 22:13:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-19 18:56:06 +00:00
|
|
|
void GPUProcessManager::EnsureVsyncIOThread() {
|
|
|
|
if (mVsyncIOThread) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mVsyncIOThread = new VsyncIOThreadHolder();
|
|
|
|
MOZ_RELEASE_ASSERT(mVsyncIOThread->Start());
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::ShutdownVsyncIOThread() { mVsyncIOThread = nullptr; }
|
|
|
|
|
2017-06-15 18:34:00 +00:00
|
|
|
void GPUProcessManager::RegisterRemoteProcessSession(
|
|
|
|
RemoteCompositorSession* aSession) {
|
2016-09-20 08:16:03 +00:00
|
|
|
mRemoteSessions.AppendElement(aSession);
|
|
|
|
}
|
|
|
|
|
2017-06-15 18:34:00 +00:00
|
|
|
void GPUProcessManager::UnregisterRemoteProcessSession(
|
|
|
|
RemoteCompositorSession* aSession) {
|
2016-09-20 08:16:03 +00:00
|
|
|
mRemoteSessions.RemoveElement(aSession);
|
|
|
|
}
|
|
|
|
|
2017-06-15 18:34:00 +00:00
|
|
|
void GPUProcessManager::RegisterInProcessSession(
|
|
|
|
InProcessCompositorSession* aSession) {
|
|
|
|
mInProcessSessions.AppendElement(aSession);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::UnregisterInProcessSession(
|
|
|
|
InProcessCompositorSession* aSession) {
|
|
|
|
mInProcessSessions.RemoveElement(aSession);
|
|
|
|
}
|
|
|
|
|
2016-09-20 08:18:50 +00:00
|
|
|
void GPUProcessManager::AddListener(GPUProcessListener* aListener) {
|
|
|
|
mListeners.AppendElement(aListener);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPUProcessManager::RemoveListener(GPUProcessListener* aListener) {
|
|
|
|
mListeners.RemoveElement(aListener);
|
|
|
|
}
|
|
|
|
|
2016-10-15 12:45:02 +00:00
|
|
|
bool GPUProcessManager::NotifyGpuObservers(const char* aTopic) {
|
2017-03-30 01:23:24 +00:00
|
|
|
if (!EnsureGPUReady()) {
|
2016-10-15 12:45:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsCString topic(aTopic);
|
|
|
|
mGPUChild->SendNotifyGpuObservers(topic);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-27 00:35:54 +00:00
|
|
|
class GPUMemoryReporter : public MemoryReportingProcess {
|
|
|
|
public:
|
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GPUMemoryReporter, override)
|
|
|
|
|
|
|
|
bool IsAlive() const override {
|
|
|
|
if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
|
|
|
|
return !!gpm->GetGPUChild();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-04-05 03:50:33 +00:00
|
|
|
bool SendRequestMemoryReport(
|
|
|
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
|
|
|
const bool& aMinimizeMemoryUsage,
|
|
|
|
const Maybe<ipc::FileDescriptor>& aDMDFile) override {
|
2017-01-27 00:35:54 +00:00
|
|
|
GPUChild* child = GetChild();
|
|
|
|
if (!child) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return child->SendRequestMemoryReport(aGeneration, aAnonymize,
|
|
|
|
aMinimizeMemoryUsage, aDMDFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t Pid() const override {
|
|
|
|
if (GPUChild* child = GetChild()) {
|
|
|
|
return (int32_t)child->OtherPid();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
GPUChild* GetChild() const {
|
|
|
|
if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
|
|
|
|
if (GPUChild* child = gpm->GetGPUChild()) {
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
~GPUMemoryReporter() = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
RefPtr<MemoryReportingProcess> GPUProcessManager::GetProcessMemoryReporter() {
|
Bug 1755381 - Avoid relaunching GPU process immediately on Android if app is in background. r=agi,aosmond
If the android system kills the GPU process to free memory while the
app is in the background, then we want to avoid immediately restarting
the GPU process.
To achieve this, we make GPUProcessManager keep track of whether it is
in the foreground or background. If HandleProcessLost() gets called
while in the background then we destroy the existing compositor
sessions as before, but return early instead of immediately
relaunching the process. If the process has not been launched when the
app later gets foregrounded then we do so then.
The final part of HandleProcessLost(), which reinitializes the content
bridges and emits the "compositor-reinitialized" signal, has been
moved to a new function ReinitializeRendering(). If the GPU process
has been disabled, this gets called as-before at the end of
HandleProcessLost(). When the GPU process is enabled, however, we now
call it from OnProcessLaunchComplete(), so that it gets called
regardless of whether the process is launched immediately or after a
delay.
While we're here, rename the functions RebuildRemoteSessions() and
RebuildInProcessSessions() to DestroyRemoteCompositorSessions() and
DestroyInProcessCompositorSessions(), to better reflect what they
actually do: the "rebuilding" part occurs later on. Also update the
mega-comment documenting the restart sequence, as it was somewhat
outdated.
In case a caller of EnsureGPUReady() gets called before the foreground
signal arrives (eg in nsBaseWidget::CreateCompositorSession() due to a
refresh tick paint), make EnsureGPUReady() launch the GPU process
itself if the GPU process is enabled but not yet launched. As a
consequence, to avoid launching the GPU process unnecessarily, change
a couple callers of EnsureGPUReady() to simply check whether the
process is enabled instead.
Additionally, guard against a null pointer deref if the compositor has
been destroyed when the widget receives a memory pressure event. This
is now more likely to occur as there may be a gap between the
compositor being destroyed and recreated.
Differential Revision: https://phabricator.services.mozilla.com/D139042
2022-02-22 15:59:13 +00:00
|
|
|
// Ensure mProcess is non-null before calling EnsureGPUReady, to avoid
|
|
|
|
// launching the process if it has not already been launched.
|
|
|
|
if (!mProcess || !EnsureGPUReady()) {
|
2017-01-27 00:35:54 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return new GPUMemoryReporter();
|
|
|
|
}
|
|
|
|
|
2021-12-15 22:18:32 +00:00
|
|
|
RefPtr<PGPUChild::TestTriggerMetricsPromise>
|
|
|
|
GPUProcessManager::TestTriggerMetrics() {
|
2021-12-01 14:35:08 +00:00
|
|
|
if (!NS_WARN_IF(!mGPUChild)) {
|
2021-12-15 22:18:32 +00:00
|
|
|
return mGPUChild->SendTestTriggerMetrics();
|
2021-12-01 14:35:08 +00:00
|
|
|
}
|
2021-12-15 22:18:32 +00:00
|
|
|
|
|
|
|
return PGPUChild::TestTriggerMetricsPromise::CreateAndReject(
|
|
|
|
ipc::ResponseRejectReason::SendError, __func__);
|
2021-12-01 14:35:08 +00:00
|
|
|
}
|
|
|
|
|
2016-05-23 07:27:01 +00:00
|
|
|
} // namespace gfx
|
|
|
|
} // namespace mozilla
|