Bug 720144 - Allow listening for draw updates and obtaining a copy of the composited surface for robocop testing. r=Cwiiis
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 30 Jan 2012 22:45:38 -0500
changeset 87022 a3e88a6dd4c9e0592a2dcf1e4ce43073b6f1ef0c
parent 87021 f123328d6dacc248a608825864ad7437ed847ab6
child 87023 2934da670f6247a91c99c2b764131b68a2431434
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersCwiiis
bugs720144
milestone12.0a1
Bug 720144 - Allow listening for draw updates and obtaining a copy of the composited surface for robocop testing. r=Cwiiis
mobile/android/base/gfx/GeckoSoftwareLayerClient.java
mobile/android/base/gfx/LayerRenderer.java
mobile/android/base/gfx/LayerView.java
--- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
+++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
@@ -107,16 +107,19 @@ public class GeckoSoftwareLayerClient ex
 
     // mUpdateViewportOnEndDraw is used to indicate that we received a
     // viewport update notification while drawing. therefore, when the
     // draw finishes, we need to update the entire viewport rather than
     // just the page size. this boolean should always be accessed from
     // inside a transaction, so no synchronization is needed.
     private boolean mUpdateViewportOnEndDraw;
 
+    /* Used by robocop for testing purposes */
+    private DrawListener mDrawListener;
+
     private static Pattern sColorPattern;
 
     public GeckoSoftwareLayerClient(Context context) {
         mContext = context;
 
         mScreenSize = new IntSize(0, 0);
         mBufferSize = new IntSize(0, 0);
         mFormat = CairoImage.FORMAT_RGB16_565;
@@ -320,16 +323,21 @@ public class GeckoSoftwareLayerClient ex
                     ((MultiTileLayer)mTileLayer).invalidate(rect);
                     ((MultiTileLayer)mTileLayer).setRenderOffset(mRenderOffset);
                 }
             } finally {
                 endTransaction(mTileLayer);
             }
         }
         Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - endDrawing");
+
+        /* Used by robocop for testing purposes */
+        if (mDrawListener != null) {
+            mDrawListener.drawFinished(x, y, width, height);
+        }
     }
 
     public ViewportMetrics getGeckoViewportMetrics() {
         // Return a copy, as we modify this inside the Gecko thread
         if (mGeckoViewport != null)
             return new ViewportMetrics(mGeckoViewport);
         return null;
     }
@@ -531,10 +539,20 @@ public class GeckoSoftwareLayerClient ex
             return Color.WHITE;
         }
 
         int r = Integer.parseInt(matcher.group(1));
         int g = Integer.parseInt(matcher.group(2));
         int b = Integer.parseInt(matcher.group(3));
         return Color.rgb(r, g, b);
     }
+
+    /** Used by robocop for testing purposes. Not for production use! */
+    public void setDrawListener(DrawListener listener) {
+        mDrawListener = listener;
+    }
+
+    /** Used by robocop for testing purposes. Not for production use! */
+    public interface DrawListener {
+        public void drawFinished(int x, int y, int width, int height);
+    }
 }
 
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -56,17 +56,17 @@ import android.graphics.Rect;
 import android.graphics.RectF;
 import android.opengl.GLSurfaceView;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.WindowManager;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
 
 /**
  * The layer renderer implements the rendering logic for a layer view.
  */
 public class LayerRenderer implements GLSurfaceView.Renderer {
     private static final String LOGTAG = "GeckoLayerRenderer";
 
     /*
@@ -90,16 +90,19 @@ public class LayerRenderer implements GL
     private RenderContext mLastPageContext;
     private int mMaxTextureSize;
 
     // Dropped frames display
     private int[] mFrameTimings;
     private int mCurrentFrame, mFrameTimingsSum, mDroppedFrames;
     private boolean mShowFrameRate;
 
+    /* Used by robocop for testing purposes */
+    private IntBuffer mPixelBuffer;
+
     public LayerRenderer(LayerView view) {
         mView = view;
 
         LayerController controller = view.getController();
 
         CairoImage backgroundImage = new BufferedCairoImage(controller.getBackgroundPattern());
         mBackgroundLayer = new SingleTileLayer(true, backgroundImage);
         mBackgroundLayer.beginTransaction(null);
@@ -241,16 +244,41 @@ public class LayerRenderer implements GL
             }
         }
 
         // If a layer update requires further work, schedule another redraw
         if (!updated)
             mView.requestRender();
 
         PanningPerfAPI.recordFrameTime();
+
+        /* Used by robocop for testing purposes */
+        IntBuffer pixelBuffer = mPixelBuffer;
+        if (updated && pixelBuffer != null) {
+            synchronized (pixelBuffer) {
+                pixelBuffer.position(0);
+                gl.glReadPixels(0, 0, (int)screenContext.viewport.width(), (int)screenContext.viewport.height(), GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuffer);
+                pixelBuffer.notify();
+            }
+        }
+    }
+
+    /** Used by robocop for testing purposes. Not for production use! */
+    IntBuffer getPixels() {
+        IntBuffer pixelBuffer = IntBuffer.allocate(mView.getWidth() * mView.getHeight());
+        synchronized (pixelBuffer) {
+            mPixelBuffer = pixelBuffer;
+            mView.requestRender();
+            try {
+                pixelBuffer.wait();
+            } catch (InterruptedException ie) {
+            }
+            mPixelBuffer = null;
+        }
+        return pixelBuffer;
     }
 
     private RenderContext createScreenContext() {
         LayerController layerController = mView.getController();
         IntSize viewportSize = new IntSize(layerController.getViewportSize());
         RectF viewport = new RectF(0.0f, 0.0f, viewportSize.width, viewportSize.height);
         FloatSize pageSize = new FloatSize(layerController.getPageSize());
         return new RenderContext(viewport, pageSize, 1.0f);
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -47,16 +47,17 @@ import org.mozilla.gecko.ui.SimpleScaleG
 import android.content.Context;
 import android.opengl.GLSurfaceView;
 import android.view.GestureDetector;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.util.Log;
+import java.nio.IntBuffer;
 import java.util.LinkedList;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 /**
  * A view rendered by the layer compositor.
@@ -232,10 +233,15 @@ public class LayerView extends GLSurface
             mRenderTimeReset = false;
             return System.nanoTime() - mRenderTime;
         }
     }
 
     public int getMaxTextureSize() {
         return mRenderer.getMaxTextureSize();
     }
+
+    /** Used by robocop for testing purposes. Not for production use! */
+    public IntBuffer getPixels() {
+        return mRenderer.getPixels();
+    }
 }