diff --git a/mobile/android/base/gfx/GLController.java b/mobile/android/base/gfx/GLController.java index ce1fda575dff..9f42f4dd3293 100644 --- a/mobile/android/base/gfx/GLController.java +++ b/mobile/android/base/gfx/GLController.java @@ -5,6 +5,9 @@ package org.mozilla.gecko.gfx; +import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.GeckoEvent; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; @@ -19,6 +22,10 @@ public class GLController { private boolean mSurfaceValid; private int mWidth, mHeight; + /* This is written by the compositor thread (while the UI thread + * is blocked on it) and read by the UI thread. */ + private volatile boolean mCompositorCreated; + private EGL10 mEGL; private EGLDisplay mEGLDisplay; private EGLConfig mEGLConfig; @@ -46,7 +53,7 @@ public class GLController { return; } } - mView.getListener().compositionResumeRequested(mWidth, mHeight); + resumeCompositor(mWidth, mHeight); } /* Wait until we are allowed to use EGL functions on the Surface backing @@ -65,6 +72,18 @@ public class GLController { synchronized void surfaceDestroyed() { mSurfaceValid = false; notifyAll(); + + // We need to coordinate with Gecko when pausing composition, to ensure + // that Gecko never executes a draw event while the compositor is paused. + // This is sent synchronously to make sure that we don't attempt to use + // any outstanding Surfaces after we call this (such as from a + // surfaceDestroyed notification), and to make sure that any in-flight + // Gecko draw events have been processed. When this returns, composition is + // definitely paused -- it'll synchronize with the Gecko event loop, which + // in turn will synchronize with the compositor thread. + if (mCompositorCreated) { + GeckoAppShell.sendEventToGeckoSync(GeckoEvent.createCompositorPauseEvent()); + } } synchronized void surfaceChanged(int newWidth, int newHeight) { @@ -74,6 +93,10 @@ public class GLController { notifyAll(); } + void compositorCreated() { + mCompositorCreated = true; + } + public boolean hasValidSurface() { return mSurfaceValid; } @@ -147,6 +170,19 @@ public class GLController { return "Error " + mEGL.eglGetError(); } + void resumeCompositor(int width, int height) { + // Asking Gecko to resume the compositor takes too long (see + // https://bugzilla.mozilla.org/show_bug.cgi?id=735230#c23), so we + // resume the compositor directly. We still need to inform Gecko about + // the compositor resuming, so that Gecko knows that it can now draw. + // It is important to not notify Gecko until after the compositor has + // been resumed, otherwise Gecko may send updates that get dropped. + if (mCompositorCreated) { + GeckoAppShell.scheduleResumeComposition(width, height); + GeckoAppShell.sendEventToGecko(GeckoEvent.createCompositorResumeEvent()); + } + } + public static class GLControllerException extends RuntimeException { public static final long serialVersionUID = 1L; @@ -155,4 +191,3 @@ public class GLController { } } } - diff --git a/mobile/android/base/gfx/GeckoLayerClient.java b/mobile/android/base/gfx/GeckoLayerClient.java index 87fd0c52c723..dd5b9c97082c 100644 --- a/mobile/android/base/gfx/GeckoLayerClient.java +++ b/mobile/android/base/gfx/GeckoLayerClient.java @@ -67,9 +67,6 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget private boolean mLastProgressiveUpdateWasLowPrecision; private boolean mProgressiveUpdateWasInDanger; - /* This is written by the compositor thread and read by the UI thread. */ - private volatile boolean mCompositorCreated; - private boolean mForceRedraw; /* The current viewport metrics. @@ -107,7 +104,6 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget mProgressiveUpdateDisplayPort = new DisplayPortMetrics(); mLastProgressiveUpdateWasLowPrecision = false; mProgressiveUpdateWasInDanger = false; - mCompositorCreated = false; mForceRedraw = true; DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); @@ -595,42 +591,13 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget } } - /** Implementation of LayerView.Listener */ - @Override - public void compositionPauseRequested() { - // We need to coordinate with Gecko when pausing composition, to ensure - // that Gecko never executes a draw event while the compositor is paused. - // This is sent synchronously to make sure that we don't attempt to use - // any outstanding Surfaces after we call this (such as from a - // surfaceDestroyed notification), and to make sure that any in-flight - // Gecko draw events have been processed. When this returns, composition is - // definitely paused -- it'll synchronize with the Gecko event loop, which - // in turn will synchronize with the compositor thread. - if (mCompositorCreated) { - GeckoAppShell.sendEventToGeckoSync(GeckoEvent.createCompositorPauseEvent()); - } - } - - /** Implementation of LayerView.Listener */ - @Override - public void compositionResumeRequested(int width, int height) { - // Asking Gecko to resume the compositor takes too long (see - // https://bugzilla.mozilla.org/show_bug.cgi?id=735230#c23), so we - // resume the compositor directly. We still need to inform Gecko about - // the compositor resuming, so that Gecko knows that it can now draw. - if (mCompositorCreated) { - GeckoAppShell.scheduleResumeComposition(width, height); - GeckoAppShell.sendEventToGecko(GeckoEvent.createCompositorResumeEvent()); - } - } - /** Implementation of LayerView.Listener */ @Override public void sizeChanged(int width, int height) { // We need to make sure a draw happens synchronously at this point, // but resizing the surface before the SurfaceView has resized will // cause a visible jump. - compositionResumeRequested(mWindowSize.width, mWindowSize.height); + mView.getGLController().resumeCompositor(mWindowSize.width, mWindowSize.height); } /** Implementation of LayerView.Listener */ @@ -641,13 +608,7 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget // We need to make this call even when the compositor isn't currently // paused (e.g. during an orientation change), to make the compositor // aware of the changed surface. - compositionResumeRequested(width, height); - } - - /** Implementation of LayerView.Listener */ - @Override - public void compositorCreated() { - mCompositorCreated = true; + mView.getGLController().resumeCompositor(width, height); } /** Implementation of PanZoomTarget */ diff --git a/mobile/android/base/gfx/LayerView.java b/mobile/android/base/gfx/LayerView.java index b391eecfcbb5..c789ceeb1a78 100644 --- a/mobile/android/base/gfx/LayerView.java +++ b/mobile/android/base/gfx/LayerView.java @@ -390,10 +390,6 @@ public class LayerView extends FrameLayout { private void onDestroyed() { mGLController.surfaceDestroyed(); - - if (mListener != null) { - mListener.compositionPauseRequested(); - } } public Object getNativeWindow() { @@ -407,8 +403,9 @@ public class LayerView extends FrameLayout { public static GLController registerCxxCompositor() { try { LayerView layerView = GeckoApp.mAppContext.getLayerView(); - layerView.mListener.compositorCreated(); - return layerView.getGLController(); + GLController controller = layerView.getGLController(); + controller.compositorCreated(); + return controller; } catch (Exception e) { Log.e(LOGTAG, "Error registering compositor!", e); return null; @@ -416,10 +413,7 @@ public class LayerView extends FrameLayout { } public interface Listener { - void compositorCreated(); void renderRequested(); - void compositionPauseRequested(); - void compositionResumeRequested(int width, int height); void sizeChanged(int width, int height); void surfaceChanged(int width, int height); }