Bug 621745 - Correctly handle EGL surfaceChange event causing glitches on resize; r=jmuizelaar
authorBenoit Girard <b56girard@gmail.com>
Mon, 22 Aug 2011 09:57:12 -0700
changeset 75686 ff19c78bded4fe275efdd9eb008619b8ee46f6cb
parent 75685 33479afad8bfdfa7ff9b7022b7a47b17d808d060
child 75687 e57b659ee5dd47e38976ab1a200fe466fd539b30
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersjmuizelaar
bugs621745
milestone9.0a1
Bug 621745 - Correctly handle EGL surfaceChange event causing glitches on resize; r=jmuizelaar
embedding/android/GeckoSurfaceView.java
widget/src/android/AndroidJavaWrappers.h
widget/src/android/nsWindow.cpp
--- a/embedding/android/GeckoSurfaceView.java
+++ b/embedding/android/GeckoSurfaceView.java
@@ -164,18 +164,40 @@ class GeckoSurfaceView
             if (c == null)
                 return;
             c.drawBitmap(bitmap, 0, 0, null);
             holder.unlockCanvasAndPost(c);
         }
     }
 
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+
+        // Force exactly one frame to render
+        // because the surface change is only seen after we
+        // have swapped the back buffer.
+        // The buffer size only changes after the next swap buffer.
+        // We need to make sure the Gecko's view resize when Android's 
+        // buffer resizes.
+        if (mDrawMode == DRAW_GLES_2) {
+            // When we get a surfaceChange event, we have 0 to n paint events 
+            // waiting in the Gecko event queue. We will make the first
+            // succeed and the abort the others.
+            mDrawSingleFrame = true;
+            if (!mInDrawing) { 
+                // Queue at least one paint event in case none are queued.
+                GeckoAppShell.scheduleRedraw();
+            }
+            GeckoAppShell.geckoEventSync();
+            mDrawSingleFrame = false;
+            mAbortDraw = false;
+        }
+
         if (mShowingSplashScreen)
             drawSplashScreen(holder, width, height);
+
         mSurfaceLock.lock();
 
         try {
             if (mInDrawing) {
                 Log.w(LOG_FILE_NAME, "surfaceChanged while mInDrawing is true!");
             }
 
             boolean invalidSize;
@@ -216,16 +238,22 @@ class GeckoSurfaceView
                 c.drawARGB(255, 255, 255, 255);
                 holder.unlockCanvasAndPost(c);
                 return;
             } else {
                 GeckoAppShell.scheduleRedraw();
             }
         } finally {
             mSurfaceLock.unlock();
+            if (mDrawMode == DRAW_GLES_2) {
+                // Force a frame to be drawn before the surfaceChange returns,
+                // otherwise we get artifacts.
+                GeckoAppShell.scheduleRedraw();
+                GeckoAppShell.geckoEventSync();
+            }
         }
 
         Object syncDrawObject = null;
         try {
             syncDrawObject = mSyncDraws.take();
         } catch (InterruptedException ie) {
             Log.e(LOG_FILE_NAME, "Threw exception while getting sync draw bitmap/buffer: ", ie);
         }
@@ -288,23 +316,33 @@ class GeckoSurfaceView
 
     /*
      * Called on Gecko thread
      */
 
     public static final int DRAW_ERROR = 0;
     public static final int DRAW_GLES_2 = 1;
     public static final int DRAW_2D = 2;
+    // Drawing is disable when the surface buffer
+    // has changed size but we haven't yet processed the
+    // resize event.
+    public static final int DRAW_DISABLED = 3;
 
     public int beginDrawing() {
         if (mInDrawing) {
             Log.e(LOG_FILE_NAME, "Recursive beginDrawing call!");
             return DRAW_ERROR;
         }
 
+        // Once we drawn our first frame after resize we can ignore
+        // the other draw events until we handle the resize events.
+        if (mAbortDraw) {
+            return DRAW_DISABLED;
+        }
+
         /* Grab the lock, which we'll hold while we're drawing.
          * It gets released in endDrawing(), and is also used in surfaceChanged
          * to make sure that we don't change our surface details while
          * we're in the middle of drawing (and especially in the middle of
          * executing beginDrawing/endDrawing).
          *
          * We might not need to hold this lock in between
          * beginDrawing/endDrawing, and might just be able to make
@@ -325,16 +363,19 @@ class GeckoSurfaceView
     }
 
     public void endDrawing() {
         if (!mInDrawing) {
             Log.e(LOG_FILE_NAME, "endDrawing without beginDrawing!");
             return;
         }
 
+       if (mDrawSingleFrame)
+            mAbortDraw = true;
+
         try {
             if (!mSurfaceValid) {
                 Log.e(LOG_FILE_NAME, "endDrawing with false mSurfaceValid");
                 return;
             }
         } finally {
             mInDrawing = false;
 
@@ -652,16 +693,20 @@ class GeckoSurfaceView
     }
 
     // Is this surface valid for drawing into?
     boolean mSurfaceValid;
 
     // Are we actively between beginDrawing/endDrawing?
     boolean mInDrawing;
 
+    // Used to finish the current buffer before changing the surface size
+    boolean mDrawSingleFrame = false;
+    boolean mAbortDraw = false;
+
     // Are we waiting for a buffer to draw in surfaceChanged?
     boolean mSyncDraw;
 
     // True if gecko requests a buffer
     int mDrawMode;
 
     static boolean mShowingSplashScreen = true;
     static String  mSplashStatusMsg = "";
--- a/widget/src/android/AndroidJavaWrappers.h
+++ b/widget/src/android/AndroidJavaWrappers.h
@@ -158,17 +158,19 @@ public:
     AndroidGeckoSurfaceView(jobject jobj) {
         Init(jobj);
     }
 
     void Init(jobject jobj);
 
     enum {
         DRAW_ERROR = 0,
-        DRAW_GLES_2 = 1
+        DRAW_GLES_2 = 1,
+        DRAW_2D = 2,
+        DRAW_DISABLED = 3
     };
 
     int BeginDrawing();
     jobject GetSoftwareDrawBitmap();
     jobject GetSoftwareDrawBuffer();
     void EndDrawing();
     void Draw2D(jobject bitmap, int width, int height);
     void Draw2D(jobject buffer, int stride);
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -1045,16 +1045,20 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
                 DrawTo(targetSurface);
             }
 
             sview.Draw2D(bytebuf, mBounds.width * 2);
         }
     } else {
         int drawType = sview.BeginDrawing();
 
+        if (drawType == AndroidGeckoSurfaceView::DRAW_DISABLED) {
+            return;
+        }
+
         if (drawType == AndroidGeckoSurfaceView::DRAW_ERROR) {
             ALOG("##### BeginDrawing failed!");
             return;
         }
 
         if (!sValidSurface) {
             sGLContext->RenewSurface();
             sValidSurface = true;