Bug 1741156 - Reinitialize compositor and request repaint after GPU process restart. r=aosmond,geckoview-reviewers,agi

This patch ensures that, following a GPU process crash, we
re-initialize the compositor and resume painting on Android.

nsWindow::GetWindowRenderer() is made to always reinitialize the
window renderer if there is none, like on other platforms. We
therefore no longer need to track whether webrender is being disabled,
as this is no longer a special case.

Previously we started the compositor as initially paused in
nsBaseWidget::CreateCompositorSession only if the widget did not yet
have a surface. Now we must unconditionally (re)start it as initially
paused, as even though the widget in the parent process may have a
surface, we will not have been able to send it to the GPU process
yet. We will send the surface to the compositor once control flow
returns to nsWindow::CreateLayerManager, where we will also now resume
the compositor if required.

Finally, we must ensure that we manually trigger a paint, both in the
parent and content processes. On other platforms this occurs
automatically following a GPU process loss through various refresh
driver events. On Android, however, nothing causes the refresh driver
to paint by itself, and we cannot receive input without first
initializing our APZ controllers, which does not happen until the
compositor receives a display list. We therefore must manually
schedule a paint. We do so from nsWindow::NotifyCompositorSessionLost
for the parent process, and BrowserChild::ReinitRendering for content
processes.

Differential Revision: https://phabricator.services.mozilla.com/D131232
This commit is contained in:
Jamie Nicol
2021-11-29 20:52:31 +00:00
parent a76b0bdd13
commit 01b7e43b00
9 changed files with 31 additions and 57 deletions

View File

@@ -3242,6 +3242,10 @@ void BrowserChild::ReinitRendering() {
nsCOMPtr<Document> doc(GetTopLevelDocument());
doc->NotifyLayerManagerRecreated();
if (mRenderLayers) {
SchedulePaint();
}
}
void BrowserChild::ReinitRenderingForDeviceReset() {

View File

@@ -11,10 +11,6 @@
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#if defined(MOZ_WIDGET_ANDROID)
# include "mozilla/widget/nsWindow.h"
#endif // defined(MOZ_WIDGET_ANDROID)
namespace mozilla {
namespace layers {
@@ -36,15 +32,5 @@ CompositorBridgeChild* CompositorSession::GetCompositorBridgeChild() {
return mCompositorBridgeChild;
}
#if defined(MOZ_WIDGET_ANDROID)
void CompositorSession::NotifyDisablingWebRender() {
if (!mWidget) {
return;
}
nsWindow* window = static_cast<nsWindow*>(mWidget);
window->NotifyDisablingWebRender();
}
#endif // defined(MOZ_WIDGET_ANDROID)
} // namespace layers
} // namespace mozilla

View File

@@ -80,8 +80,6 @@ class CompositorSession {
RefPtr<UiCompositorControllerChild> GetUiCompositorControllerChild() {
return mUiCompositorControllerChild;
}
void NotifyDisablingWebRender();
#endif // defined(MOZ_WIDGET_ANDROID)
protected:
CompositorSession(nsBaseWidget* aWidget, CompositorWidgetDelegate* aDelegate,

View File

@@ -537,15 +537,6 @@ bool GPUProcessManager::DisableWebRenderConfig(wr::WebRenderError aError,
mUnstableProcessAttempts = 1;
}
#if defined(MOZ_WIDGET_ANDROID)
// If aError is not wr::WebRenderError::INITIALIZE, nsWindow does not
// re-create LayerManager. Needs to trigger re-creating LayerManager on
// android
if (aError != wr::WebRenderError::INITIALIZE) {
NotifyDisablingWebRender();
}
#endif
return true;
}
@@ -787,18 +778,6 @@ void GPUProcessManager::RebuildInProcessSessions() {
}
}
void GPUProcessManager::NotifyDisablingWebRender() {
#if defined(MOZ_WIDGET_ANDROID)
for (const auto& session : mRemoteSessions) {
session->NotifyDisablingWebRender();
}
for (const auto& session : mInProcessSessions) {
session->NotifyDisablingWebRender();
}
#endif
}
void GPUProcessManager::NotifyRemoteActorDestroyed(
const uint64_t& aProcessToken) {
if (!NS_IsMainThread()) {

View File

@@ -230,8 +230,6 @@ class GPUProcessManager final : public GPUProcessHost::Listener {
// Returns true if WebRender was enabled and is now disabled.
bool DisableWebRenderConfig(wr::WebRenderError aError, const nsCString& aMsg);
void NotifyDisablingWebRender();
void FallbackToSoftware(const char* aMessage);
private:

View File

@@ -1710,7 +1710,6 @@ nsWindow::nsWindow()
mParent(nullptr),
mDynamicToolbarMaxHeight(0),
mIsFullScreen(false),
mIsDisablingWebRender(false),
mCompositorWidgetDelegate(nullptr) {}
nsWindow::~nsWindow() {
@@ -2167,17 +2166,11 @@ nsresult nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*) {
}
mozilla::WindowRenderer* nsWindow::GetWindowRenderer() {
if (mWindowRenderer) {
return mWindowRenderer;
}
if (mIsDisablingWebRender) {
if (!mWindowRenderer) {
CreateLayerManager();
mIsDisablingWebRender = false;
return mWindowRenderer;
}
return nullptr;
return mWindowRenderer;
}
void nsWindow::CreateLayerManager() {
@@ -2198,6 +2191,19 @@ void nsWindow::CreateLayerManager() {
LayoutDeviceIntRect rect = GetBounds();
CreateCompositor(rect.Width(), rect.Height());
if (mWindowRenderer) {
auto lvs(mLayerViewSupport.Access());
if (lvs) {
GetUiCompositorControllerChild()->OnCompositorSurfaceChanged(
mWidgetId, lvs->GetSurface());
if (!lvs->CompositorPaused()) {
CompositorBridgeChild* remoteRenderer = GetRemoteRenderer();
if (remoteRenderer) {
remoteRenderer->SendResumeAsync();
}
}
}
return;
}
@@ -2211,8 +2217,9 @@ void nsWindow::CreateLayerManager() {
}
}
void nsWindow::NotifyDisablingWebRender() {
mIsDisablingWebRender = true;
void nsWindow::NotifyCompositorSessionLost(
mozilla::layers::CompositorSession* aSession) {
nsBaseWidget::NotifyCompositorSessionLost(aSession);
RedrawAll();
}

View File

@@ -127,8 +127,6 @@ class nsWindow final : public nsBaseWidget {
void PassExternalResponse(mozilla::java::WebResponse::Param aResponse);
void NotifyDisablingWebRender();
void ShowDynamicToolbar();
void DetachNatives();
@@ -184,6 +182,9 @@ class nsWindow final : public nsBaseWidget {
WindowRenderer* GetWindowRenderer() override;
void NotifyCompositorSessionLost(
mozilla::layers::CompositorSession* aSession) override;
virtual bool NeedsPaint() override;
virtual bool WidgetPaintsBackground() override;
@@ -261,7 +262,6 @@ class nsWindow final : public nsBaseWidget {
mozilla::ScreenIntMargin mSafeAreaInsets;
bool mIsFullScreen;
bool mIsDisablingWebRender;
bool UseExternalCompositingSurface() const override { return true; }

View File

@@ -1230,9 +1230,11 @@ already_AddRefed<WebRenderLayerManager> nsBaseWidget::CreateCompositorSession(
options.SetUseWebGPU(StaticPrefs::dom_webgpu_enabled());
#ifdef MOZ_WIDGET_ANDROID
if (!GetNativeData(NS_JAVA_SURFACE)) {
// Unconditionally set the compositor as initially paused, as we have not
// yet had a chance to send the compositor surface to the GPU process. We
// will do so shortly once we have returned to nsWindow::CreateLayerManager,
// where we will also resume the compositor if required.
options.SetInitiallyPaused(true);
}
#else
options.SetInitiallyPaused(CompositorInitiallyPaused());
#endif

View File

@@ -219,7 +219,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
//
// A reference to the session object is held until this function has
// returned.
void NotifyCompositorSessionLost(
virtual void NotifyCompositorSessionLost(
mozilla::layers::CompositorSession* aSession);
already_AddRefed<mozilla::CompositorVsyncDispatcher>