Bug 1581868 - Make webrender schedule a frame immediately on resume. r=sotaro
authorJamie Nicol <jnicol@mozilla.com>
Fri, 10 Jan 2020 02:01:30 +0000
changeset 509692 467a138c74bcc536a5282d67c92b0d0df93fee4f
parent 509691 31ae6d515241fb2a0ec413760989a8fc36563bd0
child 509693 0a6e6339ac18dafe70f17ea24c41a6e1f164ec3f
push id104785
push userjnicol@mozilla.com
push dateFri, 10 Jan 2020 09:51:48 +0000
treeherderautoland@467a138c74bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1581868
milestone74.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1581868 - Make webrender schedule a frame immediately on resume. r=sotaro On webrender on android, parent-process pages (eg about:support) were not being rendered immediately after minimising then resuming the app, resulting in a black screen. The problem was that webrender believed the previous frame was still valid, and therefore that it did not need to render a new one. Content-process pages were unnaffected because we clear cached resources when the app is minimised, so we accidentally rendered a new frame on resumption. To fix this we always force a new frame to be rendered immediately on resumption. This uncovers a race condition which causes us to sometimes render frames at the wrong size when the window size has changed (for example when showing or hiding the keyboard), so that is also fixed. This also fixes a bug affecting fenix, where when opening a page in a new tab the portion of the screen where the keyboard used to be would remain black until the page had loaded. This no longer occurs because we force a composite as soon as the keyboard is hidden. Additionally, this patch reverts the original attempt at fixing this bug, as it is not necessary. Differential Revision: https://phabricator.services.mozilla.com/D59367
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/webrender_bindings/RenderCompositorEGL.cpp
gfx/webrender_bindings/RenderCompositorEGL.h
layout/base/PresShell.cpp
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -2647,16 +2647,19 @@ bool WebRenderBridgeParent::Resume() {
   if (!IsRootWebRenderBridgeParent() || mDestroyed) {
     return false;
   }
 
   if (!mApis[wr::RenderRoot::Default]->Resume()) {
     return false;
   }
 
+  // Ensure we generate and render a frame immediately.
+  ScheduleForcedGenerateFrame();
+
   mPaused = false;
   return true;
 }
 
 void WebRenderBridgeParent::ClearResources() {
   if (!mApis[wr::RenderRoot::Default]) {
     return;
   }
--- a/gfx/webrender_bindings/RenderCompositorEGL.cpp
+++ b/gfx/webrender_bindings/RenderCompositorEGL.cpp
@@ -15,17 +15,20 @@
 
 #ifdef MOZ_WAYLAND
 #  include "mozilla/widget/GtkCompositorWidget.h"
 #  include <gdk/gdk.h>
 #  include <gdk/gdkx.h>
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
+#  include "mozilla/widget/AndroidCompositorWidget.h"
 #  include "GeneratedJNIWrappers.h"
+#  include <android/native_window.h>
+#  include <android/native_window_jni.h>
 #endif
 
 namespace mozilla {
 namespace wr {
 
 /* static */
 UniquePtr<RenderCompositor> RenderCompositorEGL::Create(
     RefPtr<widget::CompositorWidget> aWidget) {
@@ -105,16 +108,28 @@ void RenderCompositorEGL::Pause() {
 }
 
 bool RenderCompositorEGL::Resume() {
 #ifdef MOZ_WIDGET_ANDROID
   // Destroy EGLSurface if it exists.
   DestroyEGLSurface();
   mEGLSurface = CreateEGLSurface();
   gl::GLContextEGL::Cast(gl())->SetEGLSurfaceOverride(mEGLSurface);
+
+  // Query the new surface size as this may have changed. We cannot use
+  // mWidget->GetClientSize() due to a race condition between nsWindow::Resize()
+  // being called and the frame being rendered after the surface is resized.
+  EGLNativeWindowType window = mWidget->AsAndroid()->GetEGLNativeWindow();
+  JNIEnv* const env = jni::GetEnvForThread();
+  ANativeWindow* const nativeWindow =
+    ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
+  const int32_t width = ANativeWindow_getWidth(nativeWindow);
+  const int32_t height = ANativeWindow_getHeight(nativeWindow);
+  mEGLSurfaceSize = LayoutDeviceIntSize(width, height);
+  ANativeWindow_release(nativeWindow);
 #elif defined(MOZ_WAYLAND)
   // Destroy EGLSurface if it exists and create a new one. We will set the
   // swap interval after MakeCurrent() has been called.
   DestroyEGLSurface();
   mEGLSurface = CreateEGLSurface();
   if (mEGLSurface != EGL_NO_SURFACE) {
     // We have a new EGL surface, which on wayland needs to be configured for
     // non-blocking buffer swaps. We need MakeCurrent() to set our current EGL
@@ -149,13 +164,17 @@ void RenderCompositorEGL::DestroyEGLSurf
   if (mEGLSurface) {
     gle->SetEGLSurfaceOverride(EGL_NO_SURFACE);
     egl->fDestroySurface(egl->Display(), mEGLSurface);
     mEGLSurface = nullptr;
   }
 }
 
 LayoutDeviceIntSize RenderCompositorEGL::GetBufferSize() {
+#ifdef MOZ_WIDGET_ANDROID
+  return mEGLSurfaceSize;
+#else
   return mWidget->GetClientSize();
+#endif
 }
 
 }  // namespace wr
 }  // namespace mozilla
--- a/gfx/webrender_bindings/RenderCompositorEGL.h
+++ b/gfx/webrender_bindings/RenderCompositorEGL.h
@@ -36,14 +36,18 @@ class RenderCompositorEGL : public Rende
   LayoutDeviceIntSize GetBufferSize() override;
 
  protected:
   EGLSurface CreateEGLSurface();
 
   void DestroyEGLSurface();
 
   EGLSurface mEGLSurface;
+#ifdef MOZ_WIDGET_ANDROID
+  // On android we must track our own surface size.
+  LayoutDeviceIntSize mEGLSurfaceSize;
+#endif
 };
 
 }  // namespace wr
 }  // namespace mozilla
 
 #endif  // MOZILLA_GFX_RENDERCOMPOSITOR_EGL_H
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -10453,29 +10453,16 @@ nsresult PresShell::SetIsActive(bool aIs
 #if defined(MOZ_WIDGET_ANDROID)
   if (changed && !aIsActive && presContext &&
       presContext->IsRootContentDocumentCrossProcess()) {
     if (BrowserChild* browserChild = BrowserChild::GetFrom(this)) {
       // Reset the dynamic toolbar offset state.
       presContext->UpdateDynamicToolbarOffset(0);
     }
   }
-
-  // When the PresShell is being reactivated, make sure that we repaint
-  // This is needed for pages living in the parent process (like about:support).
-  // Content pages are refreshed by the BrowserHost, which does not exist
-  // in parent process pages
-  if (aIsActive) {
-    if (nsIFrame* root = GetRootFrame()) {
-      FrameLayerBuilder::InvalidateAllLayersForFrame(
-          nsLayoutUtils::GetDisplayRootFrame(root));
-      root->SchedulePaint();
-    }
-  }
-
 #endif
 
   return rv;
 }
 
 RefPtr<MobileViewportManager> PresShell::GetMobileViewportManager() const {
   return mMobileViewportManager;
 }