Bug 735230 - Part 2: Add compositor pause/resume events to Gecko. r=kats
authorAli Juma <ajuma@mozilla.com>
Wed, 28 Mar 2012 18:00:32 -0400
changeset 90568 5303cc81321448cd5cea7b0dc60cf5a5a4bdc9ae
parent 90567 23f4b815ce82442b6450567f117f98571cf17178
child 90569 9435818930fabd03b6449f3124b9f25be2811eee
push id22366
push usermak77@bonardo.net
push dateThu, 29 Mar 2012 15:38:30 +0000
treeherdermozilla-central@ff3521bc6559 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs735230
milestone14.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 735230 - Part 2: Add compositor pause/resume events to Gecko. r=kats
mobile/android/base/GeckoEvent.java
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJavaWrappers.h
widget/android/nsAppShell.cpp
widget/android/nsWindow.cpp
widget/android/nsWindow.h
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -91,16 +91,18 @@ public class GeckoEvent {
     private static final int VIEWPORT = 20;
     private static final int VISITED = 21;
     private static final int NETWORK_CHANGED = 22;
     private static final int UNUSED3_EVENT = 23;
     private static final int ACTIVITY_RESUMING = 24;
     private static final int SCREENSHOT = 25;
     private static final int UNUSED2_EVENT = 26;
     private static final int SCREENORIENTATION_CHANGED = 27;
+    private static final int COMPOSITOR_PAUSE = 28;
+    private static final int COMPOSITOR_RESUME = 29;     
 
     public static final int IME_COMPOSITION_END = 0;
     public static final int IME_COMPOSITION_BEGIN = 1;
     public static final int IME_SET_TEXT = 2;
     public static final int IME_GET_TEXT = 3;
     public static final int IME_DELETE_TEXT = 4;
     public static final int IME_SET_SELECTION = 5;
     public static final int IME_GET_SELECTION = 6;
@@ -181,16 +183,24 @@ public class GeckoEvent {
     }
 
     public static GeckoEvent createKeyEvent(KeyEvent k) {
         GeckoEvent event = new GeckoEvent(KEY_EVENT);
         event.initKeyEvent(k);
         return event;
     }
 
+    public static GeckoEvent createCompositorPauseEvent() {
+        return new GeckoEvent(COMPOSITOR_PAUSE);
+    }
+
+    public static GeckoEvent createCompositorResumeEvent() {
+        return new GeckoEvent(COMPOSITOR_RESUME);
+    }
+
     private void initKeyEvent(KeyEvent k) {
         mAction = k.getAction();
         mTime = k.getEventTime();
         mMetaState = k.getMetaState();
         mFlags = k.getFlags();
         mKeyCode = k.getKeyCode();
         mUnicodeChar = k.getUnicodeChar();
         mCharacters = k.getCharacters();
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -1871,25 +1871,16 @@ AndroidBridge::IsTablet()
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return false;
 
     return env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet);
 }
 
 void
-AndroidBridge::SetCompositorParent(mozilla::layers::CompositorParent* aCompositorParent,
-                                   ::base::Thread* aCompositorThread)
-{
-#ifdef MOZ_JAVA_COMPOSITOR
-    nsWindow::SetCompositorParent(aCompositorParent, aCompositorThread);
-#endif
-}
-
-void
 AndroidBridge::SetFirstPaintViewport(float aOffsetX, float aOffsetY, float aZoom, float aPageWidth, float aPageHeight)
 {
     AndroidGeckoLayerClient *client = mLayerClient;
     if (!client)
         return;
 
     client->SetFirstPaintViewport(aOffsetX, aOffsetY, aZoom, aPageWidth, aPageHeight);
 }
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -400,18 +400,16 @@ public:
     void ClearMessageList(PRInt32 aListId);
 
     bool IsTablet();
 
     void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
     void EnableNetworkNotifications();
     void DisableNetworkNotifications();
 
-    void SetCompositorParent(mozilla::layers::CompositorParent* aCompositorParent,
-                             base::Thread* aCompositorThread);
     void SetFirstPaintViewport(float aOffsetX, float aOffsetY, float aZoom, float aPageWidth, float aPageHeight);
     void SetPageSize(float aZoom, float aPageWidth, float aPageHeight);
     void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                           nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY);
 
     jobject CreateSurface();
     void DestroySurface(jobject surface);
     void ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted, bool aBlend);
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -584,16 +584,18 @@ public:
         VIEWPORT = 20,
         VISITED = 21,
         NETWORK_CHANGED = 22,
         UNUSED3_EVENT = 23,
         ACTIVITY_RESUMING = 24,
         SCREENSHOT = 25,
         UNUSED2_EVENT = 26,
         SCREENORIENTATION_CHANGED = 27,
+        COMPOSITOR_PAUSE = 28,
+        COMPOSITOR_RESUME = 29,
         dummy_java_enum_list_end
     };
 
     enum {
         IME_COMPOSITION_END = 0,
         IME_COMPOSITION_BEGIN = 1,
         IME_SET_TEXT = 2,
         IME_GET_TEXT = 3,
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -611,16 +611,26 @@ nsAppShell::PostEvent(AndroidGeckoEvent 
             AndroidGeckoEvent *event;
             for (int i = mEventQueue.Length()-1; i >=1; i--) {
                 event = mEventQueue[i];
                 if (event->Type() == AndroidGeckoEvent::SURFACE_CREATED) {
                     mEventQueue.RemoveElementAt(i);
                     delete event;
                 }
             }
+        } else if (ae->Type() == AndroidGeckoEvent::COMPOSITOR_PAUSE ||
+                   ae->Type() == AndroidGeckoEvent::COMPOSITOR_RESUME) {
+            // Give priority to these events, but maintain their order wrt each other.
+            int i = 0;
+            while (i < mEventQueue.Length() &&
+                   (mEventQueue[i]->Type() == AndroidGeckoEvent::COMPOSITOR_PAUSE ||
+                    mEventQueue[i]->Type() == AndroidGeckoEvent::COMPOSITOR_RESUME)) {
+                i++;
+            }
+            mEventQueue.InsertElementAt(i, ae);
         } else if (ae->Type() == AndroidGeckoEvent::SENSOR_EVENT) {
             if (!mPendingSensorEvents)
                 mEventQueue.AppendElement(ae);
             mPendingSensorEvents = true;
         } else {
             mEventQueue.AppendElement(ae);
         }
 
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -209,19 +209,19 @@ nsWindow::~nsWindow()
     nsWindow *top = FindTopLevel();
     if (top->mFocus == this)
         top->mFocus = nsnull;
 #ifdef ACCESSIBILITY
     if (mRootAccessible)
         mRootAccessible = nsnull;
 #endif
     ALOG("nsWindow %p destructor", (void*)this);
-
-    AndroidBridge::Bridge()->SetCompositorParent(NULL, NULL);
-
+#ifdef MOZ_JAVA_COMPOSITOR
+    SetCompositor(NULL, NULL, NULL);
+#endif
 }
 
 bool
 nsWindow::IsTopLevel()
 {
     return mWindowType == eWindowType_toplevel ||
         mWindowType == eWindowType_dialog ||
         mWindowType == eWindowType_invisible;
@@ -767,31 +767,31 @@ nsWindow::GetLayerManager(PLayersChild*,
 
     nsWindow *topWindow = TopWindow();
 
     if (!topWindow) {
         printf_stderr(" -- no topwindow\n");
         mLayerManager = CreateBasicLayerManager();
         return mLayerManager;
     }
-
+#ifdef MOZ_JAVA_COMPOSITOR
     bool useCompositor =
         Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
 
     if (useCompositor) {
         CreateCompositor();
         if (mLayerManager) {
-            AndroidBridge::Bridge()->SetCompositorParent(mCompositorParent, mCompositorThread);
+            SetCompositor(mCompositorParent, mCompositorChild, mCompositorThread);
             return mLayerManager;
         }
 
         // If we get here, then off main thread compositing failed to initialize.
         sFailedToCreateGLContext = true;
     }
-
+#endif
     mUseAcceleratedRendering = GetShouldAccelerate();
 
     if (!mUseAcceleratedRendering ||
         sFailedToCreateGLContext)
     {
         printf_stderr(" -- creating basic, not accelerated\n");
         mLayerManager = CreateBasicLayerManager();
         return mLayerManager;
@@ -978,16 +978,41 @@ nsWindow::OnGlobalAndroidEvent(AndroidGe
             if (sNativeWindow) {
                 AndroidBridge::Bridge()->ReleaseNativeWindow(sNativeWindow);
                 sNativeWindow = nsnull;
             }
             sSurfaceExists = false;
             sValidSurface = false;
             break;
 
+#ifdef MOZ_JAVA_COMPOSITOR
+        case AndroidGeckoEvent::COMPOSITOR_PAUSE:
+            // The compositor gets paused when the app is about to go into the
+            // background. While the compositor is paused, we need to ensure that
+            // no layer tree updates (from draw events) occur, since the compositor
+            // cannot make a GL context current in order to process updates.
+            if (sCompositorChild) {
+                sCompositorChild->SendPause();
+            }
+            sCompositorPaused = true;
+            break;
+
+        case AndroidGeckoEvent::COMPOSITOR_RESUME:
+            // When we receive this, the compositor has already been told to
+            // resume. (It turns out that waiting till we reach here to tell
+            // the compositor to resume takes too long, resulting in a black
+            // flash.) This means it's now safe for layer updates to occur.
+            // Since we might have prevented one or more draw events from
+            // occurring while the compositor was paused, we need to schedule
+            // a draw event now.
+            sCompositorPaused = false;
+            win->RedrawAll();
+            break;
+#endif
+
         case AndroidGeckoEvent::GECKO_EVENT_SYNC:
             AndroidBridge::Bridge()->AcknowledgeEventSync();
             break;
 
         default:
             break;
     }
 }
@@ -1130,18 +1155,18 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
         DumpWindows();
         return;
     }
 
     nsRefPtr<nsWindow> kungFuDeathGrip(this);
 
     AndroidBridge::AutoLocalJNIFrame jniFrame;
 #ifdef MOZ_JAVA_COMPOSITOR
-    // We haven't been given a window-size yet, so do nothing
-    if (gAndroidBounds.width <= 0 || gAndroidBounds.height <= 0) {
+    // We're paused, or we haven't been given a window-size yet, so do nothing
+    if (sCompositorPaused || gAndroidBounds.width <= 0 || gAndroidBounds.height <= 0) {
         return;
     }
 
     /*
      * Check to see whether the presentation shell corresponding to the document on the screen
      * is suppressing painting. If it is, we bail out, as continuing would result in a mismatch
      * between the content on the screen and the current viewport metrics.
      */
@@ -2270,23 +2295,27 @@ nsWindow::DrawWindowOverlay(LayerManager
     client.DeactivateProgram();
 
     mLayerRendererFrame.Dispose();
 }
 
 // off-main-thread compositor fields and functions
 
 nsRefPtr<mozilla::layers::CompositorParent> nsWindow::sCompositorParent = 0;
+nsRefPtr<mozilla::layers::CompositorChild> nsWindow::sCompositorChild = 0;
 base::Thread * nsWindow::sCompositorThread = 0;
+bool nsWindow::sCompositorPaused = false;
 
 void
-nsWindow::SetCompositorParent(mozilla::layers::CompositorParent* aCompositorParent,
-                              ::base::Thread* aCompositorThread)
+nsWindow::SetCompositor(mozilla::layers::CompositorParent* aCompositorParent,
+                        mozilla::layers::CompositorChild* aCompositorChild,
+                        ::base::Thread* aCompositorThread)
 {
     sCompositorParent = aCompositorParent;
+    sCompositorChild = aCompositorChild;
     sCompositorThread = aCompositorThread;
 }
 
 void
 nsWindow::ScheduleComposite()
 {
     if (sCompositorParent) {
         sCompositorParent->ScheduleRenderOnCompositorThread();
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -56,16 +56,17 @@ class gfxASurface;
 class nsIdleService;
 
 namespace mozilla {
     class AndroidGeckoEvent;
     class AndroidKeyEvent;
 
     namespace layers {
         class CompositorParent;
+        class CompositorChild;
     }
 }
 
 class nsWindow :
     public nsBaseWidget
 {
 public:
     using nsBaseWidget::GetLayerManager;
@@ -183,18 +184,19 @@ public:
 #ifdef ACCESSIBILITY
     static bool sAccessibilityEnabled;
 #endif
 
 #ifdef MOZ_JAVA_COMPOSITOR
     virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect);
     virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect);
 
-    static void SetCompositorParent(mozilla::layers::CompositorParent* aCompositorParent,
-                                    ::base::Thread* aCompositorThread);
+    static void SetCompositor(mozilla::layers::CompositorParent* aCompositorParent,
+                              mozilla::layers::CompositorChild* aCompositorChild,
+                              ::base::Thread* aCompositorThread);
     static void ScheduleComposite();
     static void SchedulePauseComposition();
     static void ScheduleResumeComposition();
 #endif
 
 protected:
     void BringToFront();
     nsWindow *FindTopLevel();
@@ -260,13 +262,15 @@ private:
      */
     nsAccessible *DispatchAccessibleEvent();
 #endif // ACCESSIBILITY
 
 #ifdef MOZ_JAVA_COMPOSITOR
     mozilla::AndroidLayerRendererFrame mLayerRendererFrame;
 
     static nsRefPtr<mozilla::layers::CompositorParent> sCompositorParent;
+    static nsRefPtr<mozilla::layers::CompositorChild> sCompositorChild;
+    static bool sCompositorPaused;
     static base::Thread *sCompositorThread;
 #endif
 };
 
 #endif /* NSWINDOW_H_ */