Bug 732013 - Fix overdraw in LayerRenderer. r=kats
authorChris Lord <chrislord.net@gmail.com>
Thu, 01 Mar 2012 19:43:14 +0000
changeset 89285 e9c8164fab4562d3c0c5fe8a730053a9c98cb9b4
parent 89284 d1837ca496be192d091574c83ba41d09b537b5d6
child 89286 344ff7ba940f68f65eea10e1089ed953a2584564
push id22242
push userkgupta@mozilla.com
push dateWed, 14 Mar 2012 15:19:09 +0000
treeherdermozilla-central@936ef50fa498 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs732013
milestone13.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 732013 - Fix overdraw in LayerRenderer. r=kats Add an optional rectangular mask to SingleTileLayer so that we can reduce the amount of overdraw when drawing the background and checkerboard layers.
mobile/android/base/gfx/LayerRenderer.java
mobile/android/base/gfx/SingleTileLayer.java
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -569,41 +569,51 @@ public class LayerRenderer implements GL
                     pixelBuffer.notify();
                 }
             }
         }
 
         /** This function is invoked via JNI; be careful when modifying signature. */
         public void drawBackground() {
             /* Draw the background. */
+            mBackgroundLayer.setMask(getPageRect());
             mBackgroundLayer.draw(mScreenContext);
 
             /* Draw the drop shadow, if we need to. */
             Rect pageRect = getPageRect();
             RectF untransformedPageRect = new RectF(0.0f, 0.0f, pageRect.width(),
                                                     pageRect.height());
             if (!untransformedPageRect.contains(mView.getController().getViewport()))
                 mShadowLayer.draw(mPageContext);
 
+            /* Find the area the root layer will render into, to mask the scissor rect */
+            Rect rootMask = null;
+            Layer rootLayer = mView.getController().getRoot();
+            if (rootLayer != null) {
+                RectF rootBounds = rootLayer.getBounds(mPageContext);
+                rootBounds.offset(-mPageContext.viewport.left, -mPageContext.viewport.top);
+                rootMask = new Rect();
+                rootBounds.roundOut(rootMask);
+            }
+
             /* Draw the checkerboard. */
             setScissorRect();
+            mCheckerboardLayer.setMask(rootMask);
             mCheckerboardLayer.draw(mScreenContext);
             GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
         }
 
         // Draws the layer the client added to us.
         void drawRootLayer() {
             Layer rootLayer = mView.getController().getRoot();
             if (rootLayer == null) {
                 return;
             }
 
-            setScissorRect();
             rootLayer.draw(mPageContext);
-            GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
         }
 
         /** This function is invoked via JNI; be careful when modifying signature. */
         public void drawForeground() {
             Rect pageRect = getPageRect();
             LayerController controller = mView.getController();
 
             /* Draw any extra layers that were added (likely plugins) */
--- a/mobile/android/base/gfx/SingleTileLayer.java
+++ b/mobile/android/base/gfx/SingleTileLayer.java
@@ -40,88 +40,121 @@ package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.gfx.CairoImage;
 import org.mozilla.gecko.gfx.CairoUtils;
 import org.mozilla.gecko.gfx.IntSize;
 import org.mozilla.gecko.gfx.LayerController;
 import org.mozilla.gecko.gfx.TileLayer;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.RegionIterator;
 import android.opengl.GLES20;
 import android.util.Log;
 import java.nio.FloatBuffer;
 import javax.microedition.khronos.opengles.GL10;
 
 /**
  * Encapsulates the logic needed to draw a single textured tile.
  *
  * TODO: Repeating textures really should be their own type of layer.
  */
 public class SingleTileLayer extends TileLayer {
+    private static final String LOGTAG = "GeckoSingleTileLayer";
+
+    private Rect mMask;
+
     public SingleTileLayer(CairoImage image) { this(false, image); }
 
     public SingleTileLayer(boolean repeat, CairoImage image) {
         super(repeat, image);
     }
 
+    /**
+     * Set an area to mask out when rendering.
+     */
+    public void setMask(Rect aMaskRect) {
+        mMask = aMaskRect;
+    }
+
     @Override
     public void draw(RenderContext context) {
         // mTextureIDs may be null here during startup if Layer.java's draw method
         // failed to acquire the transaction lock and call performUpdates.
         if (!initialized())
             return;
 
-        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
-
         RectF bounds;
         int[] cropRect;
         Rect position = getPosition();
         RectF viewport = context.viewport;
 
         if (repeats()) {
             bounds = new RectF(0.0f, 0.0f, viewport.width(), viewport.height());
             int width = Math.round(viewport.width());
             int height = Math.round(viewport.height());
             cropRect = new int[] { 0, 0, width, height };
         } else {
             bounds = getBounds(context);
             cropRect = new int[] { 0, 0, position.width(), position.height() };
         }
 
-        float height = bounds.height();
-        float left = bounds.left - viewport.left;
-        float top = viewport.height() - (bounds.top + height - viewport.top);
+        Rect intBounds = new Rect();
+        bounds.roundOut(intBounds);
+        Region maskedBounds = new Region(intBounds);
+        if (mMask != null) {
+            maskedBounds.op(mMask, Region.Op.DIFFERENCE);
+            if (maskedBounds.isEmpty())
+                return;
+        }
 
-        float[] coords = {
-            //x, y, z, texture_x, texture_y
-            left/viewport.width(), top/viewport.height(), 0,
-            cropRect[0]/(float)position.width(), cropRect[1]/(float)position.height(),
+        // XXX Possible optimisation here, form this array so we can draw it in
+        //     a single call.
+        RegionIterator i = new RegionIterator(maskedBounds);
+        for (Rect subRect = new Rect(); i.next(subRect);) {
+            // Compensate for rounding errors at the edge of the tile caused by
+            // the roundOut above
+            RectF subRectF = new RectF(Math.max(bounds.left, (float)subRect.left),
+                                       Math.max(bounds.top, (float)subRect.top),
+                                       Math.min(bounds.right, (float)subRect.right),
+                                       Math.min(bounds.bottom, (float)subRect.bottom));
 
-            left/viewport.width(), (top+height)/viewport.height(), 0,
-            cropRect[0]/(float)position.width(), cropRect[3]/(float)position.height(),
+            float height = subRectF.height();
+            float left = subRectF.left - viewport.left;
+            float top = viewport.height() - (subRectF.top + height - viewport.top);
 
-            (left+bounds.width())/viewport.width(), top/viewport.height(), 0,
-            cropRect[2]/(float)position.width(), cropRect[1]/(float)position.height(),
+            float[] coords = {
+                //x, y, z, texture_x, texture_y
+                left/viewport.width(), top/viewport.height(), 0,
+                cropRect[0]/(float)position.width(), cropRect[1]/(float)position.height(),
 
-            (left+bounds.width())/viewport.width(), (top+height)/viewport.height(), 0,
-            cropRect[2]/(float)position.width(), cropRect[3]/(float)position.height()
-        };
+                left/viewport.width(), (top+height)/viewport.height(), 0,
+                cropRect[0]/(float)position.width(), cropRect[3]/(float)position.height(),
+
+                (left+subRectF.width())/viewport.width(), top/viewport.height(), 0,
+                cropRect[2]/(float)position.width(), cropRect[1]/(float)position.height(),
 
-        FloatBuffer coordBuffer = context.coordBuffer;
-        int positionHandle = context.positionHandle;
-        int textureHandle = context.textureHandle;
+                (left+subRectF.width())/viewport.width(), (top+height)/viewport.height(), 0,
+                cropRect[2]/(float)position.width(), cropRect[3]/(float)position.height()
+            };
+
+            FloatBuffer coordBuffer = context.coordBuffer;
+            int positionHandle = context.positionHandle;
+            int textureHandle = context.textureHandle;
 
-        // Make sure we are at position zero in the buffer in case other draw methods did not clean
-        // up after themselves
-        coordBuffer.position(0);
-        coordBuffer.put(coords);
+            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
+
+            // Make sure we are at position zero in the buffer
+            coordBuffer.position(0);
+            coordBuffer.put(coords);
 
-        // Vertex coordinates are x,y,z starting at position 0 into the buffer.
-        coordBuffer.position(0);
-        GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20, coordBuffer);
+            // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+            coordBuffer.position(0);
+            GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20, coordBuffer);
 
-        // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
-        coordBuffer.position(3);
-        GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20, coordBuffer);
-        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+            // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
+            coordBuffer.position(3);
+            GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20, coordBuffer);
+            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+        }
     }
 }