Bug 709152 - Group multiple texture uploads into a single upload. r=pcwalton
authorChris Lord <chrislord.net@gmail.com>
Thu, 22 Dec 2011 11:35:17 +0000
changeset 83251 28a81df3d02bac4562563381d56f4e6aa4563733
parent 83250 2f0774cdabf4fee4f95fd3398c7050e75902fd5e
child 83252 943ac1d43ad4799bd83d155929ed1c76d4e7b9e0
push id21744
push userbmo@edmorley.co.uk
push dateFri, 23 Dec 2011 23:56:40 +0000
treeherdermozilla-central@ede336ccaed0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspcwalton
bugs709152
milestone12.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 709152 - Group multiple texture uploads into a single upload. r=pcwalton 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);