Bug 805028 - Use ComputeRenderIntegrity to calculate accurate checkerboard. r=kats
authorChris Lord <chrislord.net@gmail.com>
Thu, 25 Oct 2012 17:23:47 +0100
changeset 111543 0592d78779d932329b37fc1bbbf67646ca9bba9f
parent 111542 221f94d010178ea6900a5f821a75972b40cb2b44
child 111544 6376bf9b9cc6a4dec8e9b154daa57e54213dac3a
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewerskats
bugs805028
milestone19.0a1
Bug 805028 - Use ComputeRenderIntegrity to calculate accurate checkerboard. r=kats Use ComputeRenderIntegrity so that checkerboarding values remain accurate when progressive tiles are enabled.
mobile/android/base/GeckoAppShell.java
mobile/android/base/gfx/LayerRenderer.java
mozglue/android/APKOpen.cpp
widget/android/AndroidJNI.cpp
widget/android/nsWindow.cpp
widget/android/nsWindow.h
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -244,16 +244,17 @@ public class GeckoAppShell
     public static native void notifyNoMessageInList(int aRequestId, long aProcessId);
     public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyReadingMessageListFailed(int aError, int aRequestId, long aProcessId);
 
     public static native void scheduleComposite();
     public static native void schedulePauseComposition();
     public static native void scheduleResumeComposition(int width, int height);
+    public static native float computeRenderIntegrity();
 
     public static native SurfaceBits getSurfaceBits(Surface surface);
 
     public static native void onFullScreenPluginHidden(View view);
 
     private static class GeckoMediaScannerClient implements MediaScannerConnectionClient {
         private String mFile = "";
         private String mMimeType = "";
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -405,22 +405,28 @@ public class LayerRenderer implements Ta
         private long mFrameStartTime;
         // A fixed snapshot of the viewport metrics that this frame is using to render content.
         private ImmutableViewportMetrics mFrameMetrics;
         // A rendering context for page-positioned layers, and one for screen-positioned layers.
         private RenderContext mPageContext, mScreenContext;
         // Whether a layer was updated.
         private boolean mUpdated;
         private final Rect mPageRect;
+        private final Rect mAbsolutePageRect;
 
         public Frame(ImmutableViewportMetrics metrics) {
             mFrameMetrics = metrics;
             mPageContext = createPageContext(metrics);
             mScreenContext = createScreenContext(metrics);
-            mPageRect = getPageRect();
+
+            Point origin = PointUtils.round(mFrameMetrics.getOrigin());
+            Rect pageRect = RectUtils.round(mFrameMetrics.getPageRect());
+            mAbsolutePageRect = new Rect(pageRect);
+            pageRect.offset(-origin.x, -origin.y);
+            mPageRect = pageRect;
         }
 
         private void setScissorRect() {
             Rect scissorRect = transformToScissorRect(mPageRect);
             GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
             GLES20.glScissor(scissorRect.left, scissorRect.top,
                              scissorRect.width(), scissorRect.height());
         }
@@ -432,23 +438,16 @@ public class LayerRenderer implements Ta
             int top = Math.max(0, rect.top);
             int right = Math.min(screenSize.width, rect.right);
             int bottom = Math.min(screenSize.height, rect.bottom);
 
             return new Rect(left, screenSize.height - bottom, right,
                             (screenSize.height - bottom) + (bottom - top));
         }
 
-        private Rect getPageRect() {
-            Point origin = PointUtils.round(mFrameMetrics.getOrigin());
-            Rect pageRect = RectUtils.round(mFrameMetrics.getPageRect());
-            pageRect.offset(-origin.x, -origin.y);
-            return pageRect;
-        }
-
         /** This function is invoked via JNI; be careful when modifying signature. */
         public void beginDrawing() {
             mFrameStartTime = SystemClock.uptimeMillis();
 
             TextureReaper.get().reap();
             TextureGenerator.get().fill();
 
             mUpdated = true;
@@ -538,19 +537,17 @@ public class LayerRenderer implements Ta
             GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT |
                            GLES20.GL_DEPTH_BUFFER_BIT);
 
             /* Draw the background. */
             mBackgroundLayer.setMask(mPageRect);
             mBackgroundLayer.draw(mScreenContext);
 
             /* Draw the drop shadow, if we need to. */
-            RectF untransformedPageRect = new RectF(0.0f, 0.0f, mPageRect.width(),
-                                                    mPageRect.height());
-            if (!untransformedPageRect.contains(mFrameMetrics.getViewport()))
+            if (!new RectF(mAbsolutePageRect).contains(mFrameMetrics.getViewport()))
                 mShadowLayer.draw(mPageContext);
 
             /* Draw the 'checkerboard'. We use gfx.show_checkerboard_pattern to
              * determine whether to draw the screenshot layer.
              */
             if (mView.checkerboardShouldShowChecks()) {
                 /* Find the area the root layer will render into, to mask the checkerboard layer */
                 Rect rootMask = getMaskForLayer(mView.getLayerClient().getRoot());
@@ -602,42 +599,49 @@ public class LayerRenderer implements Ta
             if ((rootLayer != null) &&
                 (mProfileRender || PanningPerfAPI.isRecordingCheckerboard())) {
                 // Find out how much of the viewport area is valid
                 Rect viewport = RectUtils.round(mPageContext.viewport);
                 Region validRegion = rootLayer.getValidRegion(mPageContext);
 
                 /* restrict the viewport to page bounds so we don't
                  * count overscroll as checkerboard */
-                if (!viewport.intersect(mPageRect)) {
+                if (!viewport.intersect(mAbsolutePageRect)) {
                     /* if the rectangles don't intersect
                        intersect() doesn't change viewport
                        so we set it to empty by hand */
                     viewport.setEmpty();
                 }
                 validRegion.op(viewport, Region.Op.INTERSECT);
 
-                float checkerboard = 0.0f;
+                // Check if we have total checkerboarding (there's visible
+                // page area and the valid region doesn't intersect with the
+                // viewport).
+                int screenArea = viewport.width() * viewport.height();
+                float checkerboard = (screenArea > 0 &&
+                  validRegion.quickReject(viewport)) ? 1.0f : 0.0f;
 
-                int screenArea = viewport.width() * viewport.height();
-                if (screenArea > 0 && !(validRegion.isRect() && validRegion.getBounds().equals(viewport))) {
+                if (screenArea > 0 && checkerboard < 1.0f) {
                     validRegion.op(viewport, Region.Op.REVERSE_DIFFERENCE);
 
                     // XXX The assumption here is that a Region never has overlapping
                     //     rects. This is true, as evidenced by reading the SkRegion
                     //     source, but is not mentioned in the Android documentation,
                     //     and so is liable to change.
                     //     If it does change, this code will need to be reevaluated.
                     Rect r = new Rect();
                     int checkerboardArea = 0;
                     for (RegionIterator i = new RegionIterator(validRegion); i.next(r);) {
                         checkerboardArea += r.width() * r.height();
                     }
 
                     checkerboard = checkerboardArea / (float)screenArea;
+
+                    // Add any incomplete rendering in the screen area
+                    checkerboard += (1.0 - checkerboard) * (1.0 - GeckoAppShell.computeRenderIntegrity());
                 }
 
                 PanningPerfAPI.recordCheckerboard(checkerboard);
 
                 mCompleteFramesRendered += 1.0f - checkerboard;
                 mFramesRendered ++;
 
                 if (mFrameStartTime - mProfileOutputTime > 1000) {
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -301,16 +301,17 @@ SHELL_WRAPPER1(onChangeNetworkLinkStatus
 SHELL_WRAPPER1(reportJavaCrash, jstring)
 SHELL_WRAPPER1(cameraCallbackBridge, jbyteArray)
 SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble)
 SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong)
 SHELL_WRAPPER0(bindWidgetTexture)
 SHELL_WRAPPER0(scheduleComposite)
 SHELL_WRAPPER0(schedulePauseComposition)
 SHELL_WRAPPER2(scheduleResumeComposition, jint, jint)
+SHELL_WRAPPER0_WITH_RETURN(computeRenderIntegrity, jfloat)
 SHELL_WRAPPER3_WITH_RETURN(saveMessageInSentbox, jint, jstring, jstring, jlong)
 SHELL_WRAPPER6(notifySmsSent, jint, jstring, jstring, jlong, jint, jlong)
 SHELL_WRAPPER4(notifySmsDelivered, jint, jstring, jstring, jlong)
 SHELL_WRAPPER3(notifySmsSendFailed, jint, jint, jlong)
 SHELL_WRAPPER7(notifyGetSms, jint, jstring, jstring, jstring, jlong, jint, jlong)
 SHELL_WRAPPER3(notifyGetSmsFailed, jint, jint, jlong)
 SHELL_WRAPPER3(notifySmsDeleted, jboolean, jint, jlong)
 SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong)
@@ -724,16 +725,17 @@ loadGeckoLibs(const char *apkName)
   GETFUNC(reportJavaCrash);
   GETFUNC(cameraCallbackBridge);
   GETFUNC(notifyBatteryChange);
   GETFUNC(notifySmsReceived);
   GETFUNC(bindWidgetTexture);
   GETFUNC(scheduleComposite);
   GETFUNC(schedulePauseComposition);
   GETFUNC(scheduleResumeComposition);
+  GETFUNC(computeRenderIntegrity);
   GETFUNC(saveMessageInSentbox);
   GETFUNC(notifySmsSent);
   GETFUNC(notifySmsDelivered);
   GETFUNC(notifySmsSendFailed);
   GETFUNC(notifyGetSms);
   GETFUNC(notifyGetSmsFailed);
   GETFUNC(notifySmsDeleted);
   GETFUNC(notifySmsDeleteFailed);
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -829,16 +829,22 @@ Java_org_mozilla_gecko_GeckoAppShell_sch
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_scheduleResumeComposition(JNIEnv*, jclass, jint width, jint height)
 {
     nsWindow::ScheduleResumeComposition(width, height);
 }
 
+NS_EXPORT float JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_computeRenderIntegrity(JNIEnv*, jclass)
+{
+    return nsWindow::ComputeRenderIntegrity();
+}
+
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifyFilePickerResult(JNIEnv* jenv, jclass, jstring filePath, jlong callback)
 {
     class NotifyFilePickerResultRunnable : public nsRunnable {
     public:
         NotifyFilePickerResultRunnable(nsString& fileDir, long callback) : 
             mFileDir(fileDir), mCallback(callback) {}
 
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -2278,16 +2278,30 @@ nsWindow::SchedulePauseComposition()
 void
 nsWindow::ScheduleResumeComposition(int width, int height)
 {
     if (sCompositorParent) {
         sCompositorParent->ScheduleResumeOnCompositorThread(width, height);
     }
 }
 
+float
+nsWindow::ComputeRenderIntegrity()
+{
+    if (sCompositorParent) {
+        mozilla::layers::LayerManagerOGL* manager =
+          static_cast<mozilla::layers::LayerManagerOGL*>(sCompositorParent->GetLayerManager());
+        if (manager) {
+            return manager->ComputeRenderIntegrity();
+        }
+    }
+
+    return 1.f;
+}
+
 bool
 nsWindow::WidgetPaintsBackground()
 {
     static bool sWidgetPaintsBackground = true;
     static bool sWidgetPaintsBackgroundPrefCached = false;
 
     if (!sWidgetPaintsBackgroundPrefCached) {
         sWidgetPaintsBackgroundPrefCached = true;
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -151,16 +151,17 @@ public:
     virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect);
     virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect);
 
     static void SetCompositor(mozilla::layers::CompositorParent* aCompositorParent,
                               mozilla::layers::CompositorChild* aCompositorChild);
     static void ScheduleComposite();
     static void SchedulePauseComposition();
     static void ScheduleResumeComposition(int width, int height);
+    static float ComputeRenderIntegrity();
 
     virtual bool WidgetPaintsBackground();
 #endif
 
 protected:
     void BringToFront();
     nsWindow *FindTopLevel();
     bool DrawTo(gfxASurface *targetSurface);