Bug 709152 - Group multiple texture uploads into a single upload. r=pcwalton a=akeybl
authorChris Lord <chrislord.net@gmail.com>
Thu, 22 Dec 2011 11:35:17 +0000
changeset 84787 ce658a689f5d7ccc4d186104349a2945af07c934
parent 84786 9d9046c6cc6d29b311a5327d54fc4f1591ad8f5c
child 84788 2d642175458d8994c24fd9f6a3858e68ff936d81
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspcwalton, akeybl
bugs709152
milestone11.0a2
Bug 709152 - Group multiple texture uploads into a single upload. r=pcwalton a=akeybl Instead of tracking multiple rectangles when we receive endDrawing calls, just union the dirty area into a single rectangle.
mobile/android/base/gfx/TileLayer.java
--- a/mobile/android/base/gfx/TileLayer.java
+++ b/mobile/android/base/gfx/TileLayer.java
@@ -42,36 +42,37 @@ import android.graphics.RectF;
 import android.opengl.GLES20;
 import android.util.Log;
 import javax.microedition.khronos.opengles.GL10;
 import javax.microedition.khronos.opengles.GL11Ext;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
-import java.util.ArrayList;
 
 /**
  * Base class for tile layers, which encapsulate the logic needed to draw textured tiles in OpenGL
  * ES.
  */
 public abstract class TileLayer extends Layer {
     private static final String LOGTAG = "GeckoTileLayer";
 
-    private final ArrayList<Rect> mDirtyRects;
+    private final Rect mDirtyRect;
     private final CairoImage mImage;
     private final boolean mRepeat;
     private IntSize mSize;
     private int[] mTextureIDs;
 
     public TileLayer(boolean repeat, CairoImage image) {
         mRepeat = repeat;
         mImage = image;
         mSize = new IntSize(0, 0);
-        mDirtyRects = new ArrayList<Rect>();
+
+        IntSize bufferSize = mImage.getSize();
+        mDirtyRect = new Rect();
     }
 
     @Override
     public IntSize getSize() { return mImage.getSize(); }
 
     protected boolean repeats() { return mRepeat; }
     protected int getTextureID() { return mTextureIDs[0]; }
     protected boolean initialized() { return mImage != null && mTextureIDs != null; }
@@ -84,17 +85,17 @@ public abstract class TileLayer extends 
 
     /**
      * Invalidates the given rect so that it will be uploaded again. Only valid inside a
      * transaction.
      */
     public void invalidate(Rect rect) {
         if (!inTransaction())
             throw new RuntimeException("invalidate() is only valid inside a transaction");
-        mDirtyRects.add(rect);
+        mDirtyRect.union(rect);
     }
 
     public void invalidate() {
         IntSize bufferSize = mImage.getSize();
         invalidate(new Rect(0, 0, bufferSize.width, bufferSize.height));
     }
 
     private void validateTexture() {
@@ -131,49 +132,51 @@ public abstract class TileLayer extends 
 
         // Reallocate the texture if the size has changed
         validateTexture();
 
         // Don't do any work if the image has an invalid size.
         if (!mImage.getSize().isPositive())
             return;
 
-        if (mTextureIDs == null) {
+        // If we haven't allocated a texture, assume the whole region is dirty
+        if (mTextureIDs == null)
             uploadFullTexture(gl);
-        } else {
-            for (Rect dirtyRect : mDirtyRects)
-                uploadDirtyRect(gl, dirtyRect);
-        }
+        else
+            uploadDirtyRect(gl, mDirtyRect);
 
-        mDirtyRects.clear();
+        mDirtyRect.setEmpty();
     }
 
     private void uploadFullTexture(GL10 gl) {
         IntSize bufferSize = mImage.getSize();
         uploadDirtyRect(gl, new Rect(0, 0, bufferSize.width, bufferSize.height));
     }
- 
+
     private void uploadDirtyRect(GL10 gl, Rect dirtyRect) {
+        if (dirtyRect.isEmpty())
+            return;
+
         boolean newlyCreated = false;
 
         if (mTextureIDs == null) {
             mTextureIDs = new int[1];
             gl.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
             newlyCreated = true;
         }
 
         IntSize bufferSize = mImage.getSize();
         Rect bufferRect = new Rect(0, 0, bufferSize.width, bufferSize.height);
 
         int cairoFormat = mImage.getFormat();
         CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
 
         bindAndSetGLParameters(gl);
 
-        if (newlyCreated || dirtyRect.equals(bufferRect)) {
+        if (newlyCreated || dirtyRect.contains(bufferRect)) {
             if (mSize.equals(bufferSize)) {
                 gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width, mSize.height,
                                 0, glInfo.format, glInfo.type, mImage.getBuffer());
                 return;
             } else {
                 gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width, mSize.height,
                                 0, glInfo.format, glInfo.type, null);
                 gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, bufferSize.width, bufferSize.height,
@@ -193,17 +196,18 @@ public abstract class TileLayer extends 
         int bpp = CairoUtils.bitsPerPixelForCairoFormat(cairoFormat) / 8;
         int position = dirtyRect.top * bufferSize.width * bpp;
         if (position > viewBuffer.limit()) {
             Log.e(LOGTAG, "### Position outside tile! " + dirtyRect.top);
             return;
         }
 
         viewBuffer.position(position);
-        gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, dirtyRect.top, bufferSize.width, dirtyRect.height(),
+        gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, dirtyRect.top, bufferSize.width,
+                           Math.min(bufferSize.height - dirtyRect.top, dirtyRect.height()),
                            glInfo.format, glInfo.type, viewBuffer);
     }
 
     private void bindAndSetGLParameters(GL10 gl) {
         gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]);
         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);