2011-11-18 10:28:17 -08:00
|
|
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
2012-05-21 04:12:37 -07:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2011-11-18 10:28:17 -08:00
|
|
|
|
|
|
|
package org.mozilla.gecko.gfx;
|
|
|
|
|
2012-02-08 21:13:08 -08:00
|
|
|
import org.mozilla.gecko.GeckoAppShell;
|
2012-07-27 17:53:54 -07:00
|
|
|
import org.mozilla.gecko.gfx.Layer.RenderContext;
|
2012-07-31 15:54:29 -07:00
|
|
|
import org.mozilla.gecko.mozglue.DirectBufferAllocator;
|
2012-07-15 13:20:43 -07:00
|
|
|
|
2011-11-18 10:28:17 -08:00
|
|
|
import android.content.Context;
|
2011-12-09 07:01:31 -08:00
|
|
|
import android.content.SharedPreferences;
|
2011-11-23 11:07:47 -08:00
|
|
|
import android.graphics.Point;
|
2011-11-18 10:28:17 -08:00
|
|
|
import android.graphics.Rect;
|
|
|
|
import android.graphics.RectF;
|
2012-02-02 01:02:32 -08:00
|
|
|
import android.graphics.Region;
|
|
|
|
import android.graphics.RegionIterator;
|
2012-02-08 21:13:08 -08:00
|
|
|
import android.opengl.GLES20;
|
2011-12-09 07:01:26 -08:00
|
|
|
import android.os.SystemClock;
|
2011-11-18 10:28:17 -08:00
|
|
|
import android.util.Log;
|
2012-07-15 13:20:43 -07:00
|
|
|
|
2012-02-08 21:13:08 -08:00
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import java.nio.ByteOrder;
|
|
|
|
import java.nio.FloatBuffer;
|
2012-01-30 19:45:38 -08:00
|
|
|
import java.nio.IntBuffer;
|
2012-05-11 07:54:51 -07:00
|
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
2011-11-18 10:28:17 -08:00
|
|
|
|
2012-07-27 17:53:54 -07:00
|
|
|
import javax.microedition.khronos.egl.EGLConfig;
|
|
|
|
|
2011-11-18 10:28:17 -08:00
|
|
|
/**
|
|
|
|
* The layer renderer implements the rendering logic for a layer view.
|
|
|
|
*/
|
2012-07-17 17:54:54 -07:00
|
|
|
public class LayerRenderer {
|
2011-12-09 13:05:24 -08:00
|
|
|
private static final String LOGTAG = "GeckoLayerRenderer";
|
2012-02-02 01:02:32 -08:00
|
|
|
private static final String PROFTAG = "GeckoLayerRendererProf";
|
2011-12-09 13:05:24 -08:00
|
|
|
|
2011-12-09 07:01:26 -08:00
|
|
|
/*
|
|
|
|
* The amount of time a frame is allowed to take to render before we declare it a dropped
|
|
|
|
* frame.
|
|
|
|
*/
|
|
|
|
private static final int MAX_FRAME_TIME = 16; /* 1000 ms / 60 FPS */
|
|
|
|
|
2012-02-29 11:08:23 -08:00
|
|
|
private static final int FRAME_RATE_METER_WIDTH = 128;
|
2011-12-09 07:01:28 -08:00
|
|
|
private static final int FRAME_RATE_METER_HEIGHT = 32;
|
|
|
|
|
2012-02-08 07:46:26 -08:00
|
|
|
private final LayerView mView;
|
2012-01-20 06:27:09 -08:00
|
|
|
private final SingleTileLayer mBackgroundLayer;
|
2012-04-24 12:13:36 -07:00
|
|
|
private final ScreenshotLayer mCheckerboardLayer;
|
2011-12-01 14:05:41 -08:00
|
|
|
private final NinePatchTileLayer mShadowLayer;
|
2012-02-28 15:08:43 -08:00
|
|
|
private TextLayer mFrameRateLayer;
|
2011-12-01 14:05:41 -08:00
|
|
|
private final ScrollbarLayer mHorizScrollLayer;
|
|
|
|
private final ScrollbarLayer mVertScrollLayer;
|
2011-12-09 13:05:24 -08:00
|
|
|
private final FadeRunnable mFadeRunnable;
|
2012-05-10 06:46:53 -07:00
|
|
|
private ByteBuffer mCoordByteBuffer;
|
|
|
|
private FloatBuffer mCoordBuffer;
|
2011-12-09 13:05:24 -08:00
|
|
|
private RenderContext mLastPageContext;
|
2011-12-15 15:45:52 -08:00
|
|
|
private int mMaxTextureSize;
|
2012-04-27 09:54:18 -07:00
|
|
|
private int mBackgroundColor;
|
2011-11-18 10:28:17 -08:00
|
|
|
|
2012-05-11 07:54:51 -07:00
|
|
|
private CopyOnWriteArrayList<Layer> mExtraLayers = new CopyOnWriteArrayList<Layer>();
|
2012-01-31 06:40:58 -08:00
|
|
|
|
2011-12-09 07:01:26 -08:00
|
|
|
// Dropped frames display
|
|
|
|
private int[] mFrameTimings;
|
|
|
|
private int mCurrentFrame, mFrameTimingsSum, mDroppedFrames;
|
2011-11-18 10:28:17 -08:00
|
|
|
|
2012-02-02 01:02:32 -08:00
|
|
|
// Render profiling output
|
|
|
|
private int mFramesRendered;
|
|
|
|
private float mCompleteFramesRendered;
|
|
|
|
private boolean mProfileRender;
|
|
|
|
private long mProfileOutputTime;
|
|
|
|
|
2012-01-30 19:45:38 -08:00
|
|
|
/* Used by robocop for testing purposes */
|
|
|
|
private IntBuffer mPixelBuffer;
|
|
|
|
|
2012-02-08 21:13:08 -08:00
|
|
|
// Used by GLES 2.0
|
|
|
|
private int mProgram;
|
|
|
|
private int mPositionHandle;
|
|
|
|
private int mTextureHandle;
|
|
|
|
private int mSampleHandle;
|
|
|
|
private int mTMatrixHandle;
|
|
|
|
|
|
|
|
// column-major matrix applied to each vertex to shift the viewport from
|
|
|
|
// one ranging from (-1, -1),(1,1) to (0,0),(1,1) and to scale all sizes by
|
|
|
|
// a factor of 2 to fill up the screen
|
2012-03-02 04:12:08 -08:00
|
|
|
public static final float[] DEFAULT_TEXTURE_MATRIX = {
|
2012-02-08 21:13:08 -08:00
|
|
|
2.0f, 0.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 2.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 2.0f, 0.0f,
|
|
|
|
-1.0f, -1.0f, 0.0f, 1.0f
|
|
|
|
};
|
|
|
|
|
|
|
|
private static final int COORD_BUFFER_SIZE = 20;
|
|
|
|
|
|
|
|
// The shaders run on the GPU directly, the vertex shader is only applying the
|
|
|
|
// matrix transform detailed above
|
2012-05-28 08:35:20 -07:00
|
|
|
|
|
|
|
// Note we flip the y-coordinate in the vertex shader from a
|
|
|
|
// coordinate system with (0,0) in the top left to one with (0,0) in
|
|
|
|
// the bottom left.
|
|
|
|
|
2012-03-02 04:12:08 -08:00
|
|
|
public static final String DEFAULT_VERTEX_SHADER =
|
2012-02-08 21:13:08 -08:00
|
|
|
"uniform mat4 uTMatrix;\n" +
|
|
|
|
"attribute vec4 vPosition;\n" +
|
|
|
|
"attribute vec2 aTexCoord;\n" +
|
|
|
|
"varying vec2 vTexCoord;\n" +
|
|
|
|
"void main() {\n" +
|
|
|
|
" gl_Position = uTMatrix * vPosition;\n" +
|
2012-05-28 08:35:20 -07:00
|
|
|
" vTexCoord.x = aTexCoord.x;\n" +
|
|
|
|
" vTexCoord.y = 1.0 - aTexCoord.y;\n" +
|
2012-02-08 21:13:08 -08:00
|
|
|
"}\n";
|
|
|
|
|
2012-05-24 13:44:10 -07:00
|
|
|
// We use highp because the screenshot textures
|
|
|
|
// we use are large and we stretch them alot
|
|
|
|
// so we need all the precision we can get.
|
|
|
|
// Unfortunately, highp is not required by ES 2.0
|
|
|
|
// so on GPU's like Mali we end up getting mediump
|
2012-03-02 04:12:08 -08:00
|
|
|
public static final String DEFAULT_FRAGMENT_SHADER =
|
2012-05-24 13:44:10 -07:00
|
|
|
"precision highp float;\n" +
|
2012-02-08 21:13:08 -08:00
|
|
|
"varying vec2 vTexCoord;\n" +
|
|
|
|
"uniform sampler2D sTexture;\n" +
|
|
|
|
"void main() {\n" +
|
2012-05-28 08:35:20 -07:00
|
|
|
" gl_FragColor = texture2D(sTexture, vTexCoord);\n" +
|
2012-02-08 21:13:08 -08:00
|
|
|
"}\n";
|
|
|
|
|
2012-06-14 09:08:51 -07:00
|
|
|
public void setCheckerboardBitmap(ByteBuffer data, int width, int height, RectF pageRect, Rect copyRect) {
|
2012-04-24 12:13:36 -07:00
|
|
|
try {
|
2012-07-23 12:34:16 -07:00
|
|
|
mCheckerboardLayer.setBitmap(data, width, height, copyRect);
|
|
|
|
} catch (IllegalArgumentException ex) {
|
|
|
|
Log.e(LOGTAG, "error setting bitmap: ", ex);
|
2012-04-24 12:13:36 -07:00
|
|
|
}
|
|
|
|
mCheckerboardLayer.beginTransaction();
|
|
|
|
try {
|
2012-05-30 08:27:05 -07:00
|
|
|
mCheckerboardLayer.setPosition(RectUtils.round(pageRect));
|
2012-04-24 12:13:36 -07:00
|
|
|
mCheckerboardLayer.invalidate();
|
|
|
|
} finally {
|
|
|
|
mCheckerboardLayer.endTransaction();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void resetCheckerboard() {
|
|
|
|
mCheckerboardLayer.reset();
|
|
|
|
}
|
|
|
|
|
2012-02-08 07:46:26 -08:00
|
|
|
public LayerRenderer(LayerView view) {
|
2011-11-18 10:28:17 -08:00
|
|
|
mView = view;
|
|
|
|
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
LayerController controller = view.getController();
|
|
|
|
|
|
|
|
CairoImage backgroundImage = new BufferedCairoImage(controller.getBackgroundPattern());
|
2012-01-20 06:27:09 -08:00
|
|
|
mBackgroundLayer = new SingleTileLayer(true, backgroundImage);
|
|
|
|
|
2012-04-24 12:13:36 -07:00
|
|
|
mCheckerboardLayer = ScreenshotLayer.create();
|
2011-12-01 14:05:41 -08:00
|
|
|
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
CairoImage shadowImage = new BufferedCairoImage(controller.getShadowPattern());
|
2011-12-01 14:05:41 -08:00
|
|
|
mShadowLayer = new NinePatchTileLayer(shadowImage);
|
|
|
|
|
2012-03-02 04:12:08 -08:00
|
|
|
mHorizScrollLayer = ScrollbarLayer.create(this, false);
|
|
|
|
mVertScrollLayer = ScrollbarLayer.create(this, true);
|
2011-12-09 13:05:24 -08:00
|
|
|
mFadeRunnable = new FadeRunnable();
|
2011-11-18 10:28:17 -08:00
|
|
|
|
2011-12-09 07:01:26 -08:00
|
|
|
mFrameTimings = new int[60];
|
|
|
|
mCurrentFrame = mFrameTimingsSum = mDroppedFrames = 0;
|
2012-02-08 21:13:08 -08:00
|
|
|
|
|
|
|
// Initialize the FloatBuffer that will be used to store all vertices and texture
|
|
|
|
// coordinates in draw() commands.
|
2012-07-31 15:54:29 -07:00
|
|
|
mCoordByteBuffer = DirectBufferAllocator.allocate(COORD_BUFFER_SIZE * 4);
|
2012-05-10 06:46:53 -07:00
|
|
|
mCoordByteBuffer.order(ByteOrder.nativeOrder());
|
|
|
|
mCoordBuffer = mCoordByteBuffer.asFloatBuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void finalize() throws Throwable {
|
|
|
|
try {
|
2012-07-31 15:54:29 -07:00
|
|
|
DirectBufferAllocator.free(mCoordByteBuffer);
|
|
|
|
mCoordByteBuffer = null;
|
|
|
|
mCoordBuffer = null;
|
2012-05-10 06:46:53 -07:00
|
|
|
} finally {
|
|
|
|
super.finalize();
|
|
|
|
}
|
2011-11-18 10:28:17 -08:00
|
|
|
}
|
|
|
|
|
2012-06-03 14:49:50 -07:00
|
|
|
void onSurfaceCreated(EGLConfig config) {
|
2012-02-02 01:02:32 -08:00
|
|
|
checkMonitoringEnabled();
|
2012-03-02 04:12:08 -08:00
|
|
|
createDefaultProgram();
|
|
|
|
activateDefaultProgram();
|
2012-02-13 12:27:09 -08:00
|
|
|
}
|
2011-12-09 07:01:31 -08:00
|
|
|
|
2012-03-02 04:12:08 -08:00
|
|
|
public void createDefaultProgram() {
|
|
|
|
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DEFAULT_VERTEX_SHADER);
|
|
|
|
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DEFAULT_FRAGMENT_SHADER);
|
2012-02-08 21:13:08 -08:00
|
|
|
|
|
|
|
mProgram = GLES20.glCreateProgram();
|
|
|
|
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
|
|
|
|
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
|
|
|
|
GLES20.glLinkProgram(mProgram); // creates OpenGL program executables
|
|
|
|
|
|
|
|
// Get handles to the vertex shader's vPosition, aTexCoord, sTexture, and uTMatrix members.
|
|
|
|
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
|
|
|
|
mTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoord");
|
|
|
|
mSampleHandle = GLES20.glGetUniformLocation(mProgram, "sTexture");
|
|
|
|
mTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uTMatrix");
|
2011-12-15 15:45:52 -08:00
|
|
|
|
|
|
|
int maxTextureSizeResult[] = new int[1];
|
2012-02-08 21:13:08 -08:00
|
|
|
GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSizeResult, 0);
|
2011-12-15 15:45:52 -08:00
|
|
|
mMaxTextureSize = maxTextureSizeResult[0];
|
2012-02-13 12:27:09 -08:00
|
|
|
}
|
2012-01-31 06:40:58 -08:00
|
|
|
|
2012-02-13 12:27:09 -08:00
|
|
|
// Activates the shader program.
|
2012-03-02 04:12:08 -08:00
|
|
|
public void activateDefaultProgram() {
|
2012-02-08 21:13:08 -08:00
|
|
|
// Add the program to the OpenGL environment
|
|
|
|
GLES20.glUseProgram(mProgram);
|
|
|
|
|
|
|
|
// Set the transformation matrix
|
2012-03-02 04:12:08 -08:00
|
|
|
GLES20.glUniformMatrix4fv(mTMatrixHandle, 1, false, DEFAULT_TEXTURE_MATRIX, 0);
|
2012-02-08 21:13:08 -08:00
|
|
|
|
2012-02-13 12:27:09 -08:00
|
|
|
// Enable the arrays from which we get the vertex and texture coordinates
|
2012-02-08 21:13:08 -08:00
|
|
|
GLES20.glEnableVertexAttribArray(mPositionHandle);
|
|
|
|
GLES20.glEnableVertexAttribArray(mTextureHandle);
|
|
|
|
|
|
|
|
GLES20.glUniform1i(mSampleHandle, 0);
|
|
|
|
|
2012-02-10 23:50:13 -08:00
|
|
|
// TODO: Move these calls into a separate deactivate() call that is called after the
|
|
|
|
// underlay and overlay are rendered.
|
2012-02-13 12:27:09 -08:00
|
|
|
}
|
2012-02-10 23:50:13 -08:00
|
|
|
|
2012-02-13 12:27:09 -08:00
|
|
|
// Deactivates the shader program. This must be done to avoid crashes after returning to the
|
|
|
|
// Gecko C++ compositor from Java.
|
2012-03-02 04:12:08 -08:00
|
|
|
public void deactivateDefaultProgram() {
|
2012-02-10 23:50:13 -08:00
|
|
|
GLES20.glDisableVertexAttribArray(mTextureHandle);
|
|
|
|
GLES20.glDisableVertexAttribArray(mPositionHandle);
|
|
|
|
GLES20.glUseProgram(0);
|
2011-12-15 15:45:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
public int getMaxTextureSize() {
|
|
|
|
return mMaxTextureSize;
|
2011-11-18 10:28:17 -08:00
|
|
|
}
|
|
|
|
|
2012-01-31 06:40:58 -08:00
|
|
|
public void addLayer(Layer layer) {
|
2012-05-11 07:54:51 -07:00
|
|
|
synchronized (mExtraLayers) {
|
2012-01-31 06:40:58 -08:00
|
|
|
if (mExtraLayers.contains(layer)) {
|
|
|
|
mExtraLayers.remove(layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
mExtraLayers.add(layer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeLayer(Layer layer) {
|
2012-05-11 07:54:51 -07:00
|
|
|
synchronized (mExtraLayers) {
|
2012-01-31 06:40:58 -08:00
|
|
|
mExtraLayers.remove(layer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-02 01:02:32 -08:00
|
|
|
private void printCheckerboardStats() {
|
|
|
|
Log.d(PROFTAG, "Frames rendered over last 1000ms: " + mCompleteFramesRendered + "/" + mFramesRendered);
|
|
|
|
mFramesRendered = 0;
|
|
|
|
mCompleteFramesRendered = 0;
|
|
|
|
}
|
|
|
|
|
2012-01-30 19:45:38 -08:00
|
|
|
/** Used by robocop for testing purposes. Not for production use! */
|
|
|
|
IntBuffer getPixels() {
|
2012-02-08 07:46:26 -08:00
|
|
|
IntBuffer pixelBuffer = IntBuffer.allocate(mView.getWidth() * mView.getHeight());
|
2012-01-30 19:45:38 -08:00
|
|
|
synchronized (pixelBuffer) {
|
|
|
|
mPixelBuffer = pixelBuffer;
|
|
|
|
mView.requestRender();
|
|
|
|
try {
|
|
|
|
pixelBuffer.wait();
|
|
|
|
} catch (InterruptedException ie) {
|
|
|
|
}
|
|
|
|
mPixelBuffer = null;
|
|
|
|
}
|
|
|
|
return pixelBuffer;
|
2011-12-01 14:05:41 -08:00
|
|
|
}
|
2011-11-21 15:15:29 -08:00
|
|
|
|
2012-04-17 22:34:05 -07:00
|
|
|
private RenderContext createScreenContext(ImmutableViewportMetrics metrics) {
|
|
|
|
RectF viewport = new RectF(0.0f, 0.0f, metrics.getWidth(), metrics.getHeight());
|
2012-05-23 07:49:52 -07:00
|
|
|
RectF pageRect = new RectF(metrics.getPageRect());
|
|
|
|
return createContext(viewport, pageRect, 1.0f);
|
2011-11-18 10:28:17 -08:00
|
|
|
}
|
|
|
|
|
2012-04-17 22:34:05 -07:00
|
|
|
private RenderContext createPageContext(ImmutableViewportMetrics metrics) {
|
2012-03-17 08:08:22 -07:00
|
|
|
Rect viewport = RectUtils.round(metrics.getViewport());
|
2012-05-23 07:49:52 -07:00
|
|
|
RectF pageRect = metrics.getPageRect();
|
2012-03-17 08:08:22 -07:00
|
|
|
float zoomFactor = metrics.zoomFactor;
|
2012-05-23 07:49:52 -07:00
|
|
|
return createContext(new RectF(viewport), pageRect, zoomFactor);
|
2012-02-09 22:58:18 -08:00
|
|
|
}
|
|
|
|
|
2012-05-23 07:49:52 -07:00
|
|
|
private RenderContext createContext(RectF viewport, RectF pageRect, float zoomFactor) {
|
2012-05-24 08:02:49 -07:00
|
|
|
return new RenderContext(viewport, pageRect, zoomFactor, mPositionHandle, mTextureHandle,
|
2012-02-09 22:58:18 -08:00
|
|
|
mCoordBuffer);
|
2011-11-18 10:28:17 -08:00
|
|
|
}
|
|
|
|
|
2011-12-09 07:01:26 -08:00
|
|
|
private void updateDroppedFrames(long frameStartTime) {
|
|
|
|
int frameElapsedTime = (int)(SystemClock.uptimeMillis() - frameStartTime);
|
2011-11-30 09:27:13 -08:00
|
|
|
|
2011-12-09 07:01:26 -08:00
|
|
|
/* Update the running statistics. */
|
|
|
|
mFrameTimingsSum -= mFrameTimings[mCurrentFrame];
|
|
|
|
mFrameTimingsSum += frameElapsedTime;
|
|
|
|
mDroppedFrames -= (mFrameTimings[mCurrentFrame] + 1) / MAX_FRAME_TIME;
|
|
|
|
mDroppedFrames += (frameElapsedTime + 1) / MAX_FRAME_TIME;
|
2011-11-18 18:07:14 -08:00
|
|
|
|
2012-01-06 12:21:49 -08:00
|
|
|
mFrameTimings[mCurrentFrame] = frameElapsedTime;
|
2011-12-09 07:01:26 -08:00
|
|
|
mCurrentFrame = (mCurrentFrame + 1) % mFrameTimings.length;
|
2011-11-30 09:27:13 -08:00
|
|
|
|
2011-12-09 07:01:26 -08:00
|
|
|
int averageTime = mFrameTimingsSum / mFrameTimings.length;
|
2012-02-23 10:25:19 -08:00
|
|
|
mFrameRateLayer.beginTransaction(); // called on compositor thread
|
2011-12-09 07:01:26 -08:00
|
|
|
try {
|
|
|
|
mFrameRateLayer.setText(averageTime + " ms/" + mDroppedFrames);
|
|
|
|
} finally {
|
|
|
|
mFrameRateLayer.endTransaction();
|
2011-11-18 10:28:17 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-09 07:01:28 -08:00
|
|
|
/* Given the new dimensions for the surface, moves the frame rate layer appropriately. */
|
|
|
|
private void moveFrameRateLayer(int width, int height) {
|
2012-02-23 10:25:19 -08:00
|
|
|
mFrameRateLayer.beginTransaction(); // called on compositor thread
|
2011-12-09 07:01:28 -08:00
|
|
|
try {
|
2012-02-26 07:47:47 -08:00
|
|
|
Rect position = new Rect(width - FRAME_RATE_METER_WIDTH - 8,
|
|
|
|
height - FRAME_RATE_METER_HEIGHT + 8,
|
|
|
|
width - 8,
|
|
|
|
height + 8);
|
|
|
|
mFrameRateLayer.setPosition(position);
|
2011-12-09 07:01:28 -08:00
|
|
|
} finally {
|
|
|
|
mFrameRateLayer.endTransaction();
|
|
|
|
}
|
|
|
|
}
|
2011-12-09 07:01:31 -08:00
|
|
|
|
2012-02-29 11:08:23 -08:00
|
|
|
void checkMonitoringEnabled() {
|
2011-12-09 07:01:31 -08:00
|
|
|
/* Do this I/O off the main thread to minimize its impact on startup time. */
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
Context context = mView.getContext();
|
|
|
|
SharedPreferences preferences = context.getSharedPreferences("GeckoApp", 0);
|
2012-02-28 15:08:43 -08:00
|
|
|
if (preferences.getBoolean("showFrameRate", false)) {
|
|
|
|
IntSize frameRateLayerSize = new IntSize(FRAME_RATE_METER_WIDTH, FRAME_RATE_METER_HEIGHT);
|
|
|
|
mFrameRateLayer = TextLayer.create(frameRateLayerSize, "-- ms/--");
|
|
|
|
moveFrameRateLayer(mView.getWidth(), mView.getHeight());
|
|
|
|
}
|
2012-02-02 01:02:32 -08:00
|
|
|
mProfileRender = Log.isLoggable(PROFTAG, Log.DEBUG);
|
2011-12-09 07:01:31 -08:00
|
|
|
}
|
2012-01-02 21:57:06 -08:00
|
|
|
}).start();
|
2011-12-09 07:01:31 -08:00
|
|
|
}
|
2011-12-09 13:05:24 -08:00
|
|
|
|
2012-02-08 21:13:08 -08:00
|
|
|
/*
|
|
|
|
* create a vertex shader type (GLES20.GL_VERTEX_SHADER)
|
|
|
|
* or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
|
|
|
|
*/
|
2012-03-02 04:12:08 -08:00
|
|
|
public static int loadShader(int type, String shaderCode) {
|
2012-02-08 21:13:08 -08:00
|
|
|
int shader = GLES20.glCreateShader(type);
|
|
|
|
GLES20.glShaderSource(shader, shaderCode);
|
|
|
|
GLES20.glCompileShader(shader);
|
|
|
|
return shader;
|
2012-01-23 20:10:24 -08:00
|
|
|
}
|
|
|
|
|
2012-04-17 22:34:05 -07:00
|
|
|
public Frame createFrame(ImmutableViewportMetrics metrics) {
|
|
|
|
return new Frame(metrics);
|
2012-02-09 22:58:18 -08:00
|
|
|
}
|
|
|
|
|
2012-07-17 17:54:54 -07:00
|
|
|
class FadeRunnable implements Runnable {
|
2011-12-09 13:05:24 -08:00
|
|
|
private boolean mStarted;
|
|
|
|
private long mRunAt;
|
|
|
|
|
|
|
|
void scheduleStartFade(long delay) {
|
|
|
|
mRunAt = SystemClock.elapsedRealtime() + delay;
|
|
|
|
if (!mStarted) {
|
|
|
|
mView.postDelayed(this, delay);
|
|
|
|
mStarted = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void scheduleNextFadeFrame() {
|
|
|
|
if (mStarted) {
|
|
|
|
Log.e(LOGTAG, "scheduleNextFadeFrame() called while scheduled for starting fade");
|
|
|
|
}
|
|
|
|
mView.postDelayed(this, 1000L / 60L); // request another frame at 60fps
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean timeToFade() {
|
|
|
|
return !mStarted;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
long timeDelta = mRunAt - SystemClock.elapsedRealtime();
|
|
|
|
if (timeDelta > 0) {
|
|
|
|
// the run-at time was pushed back, so reschedule
|
|
|
|
mView.postDelayed(this, timeDelta);
|
|
|
|
} else {
|
|
|
|
// reached the run-at time, execute
|
|
|
|
mStarted = false;
|
|
|
|
mView.requestRender();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-08 22:27:01 -08:00
|
|
|
|
2012-07-17 17:54:54 -07:00
|
|
|
public class Frame {
|
2012-02-08 22:27:01 -08:00
|
|
|
// The timestamp recording the start of this frame.
|
|
|
|
private long mFrameStartTime;
|
2012-04-17 22:34:05 -07:00
|
|
|
// A fixed snapshot of the viewport metrics that this frame is using to render content.
|
|
|
|
private ImmutableViewportMetrics mFrameMetrics;
|
2012-02-08 22:27:01 -08:00
|
|
|
// 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;
|
2012-04-05 12:58:42 -07:00
|
|
|
private final Rect mPageRect;
|
2012-02-08 22:27:01 -08:00
|
|
|
|
2012-04-17 22:34:05 -07:00
|
|
|
public Frame(ImmutableViewportMetrics metrics) {
|
|
|
|
mFrameMetrics = metrics;
|
|
|
|
mPageContext = createPageContext(metrics);
|
|
|
|
mScreenContext = createScreenContext(metrics);
|
2012-04-05 12:58:42 -07:00
|
|
|
mPageRect = getPageRect();
|
2012-02-08 22:27:01 -08:00
|
|
|
}
|
|
|
|
|
2012-02-13 20:20:38 -08:00
|
|
|
private void setScissorRect() {
|
2012-04-05 12:58:42 -07:00
|
|
|
Rect scissorRect = transformToScissorRect(mPageRect);
|
2012-02-13 20:20:38 -08:00
|
|
|
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
|
|
|
|
GLES20.glScissor(scissorRect.left, scissorRect.top,
|
|
|
|
scissorRect.width(), scissorRect.height());
|
|
|
|
}
|
|
|
|
|
2012-04-17 22:34:05 -07:00
|
|
|
private Rect transformToScissorRect(Rect rect) {
|
|
|
|
IntSize screenSize = new IntSize(mFrameMetrics.getSize());
|
|
|
|
|
|
|
|
int left = Math.max(0, rect.left);
|
|
|
|
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());
|
2012-05-23 07:49:52 -07:00
|
|
|
Rect pageRect = RectUtils.round(mFrameMetrics.getPageRect());
|
|
|
|
pageRect.offset(-origin.x, -origin.y);
|
|
|
|
return pageRect;
|
2012-04-17 22:34:05 -07:00
|
|
|
}
|
|
|
|
|
2012-02-23 10:25:19 -08:00
|
|
|
/** This function is invoked via JNI; be careful when modifying signature. */
|
2012-02-08 22:27:01 -08:00
|
|
|
public void beginDrawing() {
|
|
|
|
mFrameStartTime = SystemClock.uptimeMillis();
|
|
|
|
|
|
|
|
TextureReaper.get().reap();
|
|
|
|
TextureGenerator.get().fill();
|
|
|
|
|
|
|
|
mUpdated = true;
|
|
|
|
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
Layer rootLayer = mView.getController().getRoot();
|
2012-02-08 22:27:01 -08:00
|
|
|
|
|
|
|
if (!mPageContext.fuzzyEquals(mLastPageContext)) {
|
|
|
|
// the viewport or page changed, so show the scrollbars again
|
|
|
|
// as per UX decision
|
|
|
|
mVertScrollLayer.unfade();
|
|
|
|
mHorizScrollLayer.unfade();
|
|
|
|
mFadeRunnable.scheduleStartFade(ScrollbarLayer.FADE_DELAY);
|
|
|
|
} else if (mFadeRunnable.timeToFade()) {
|
|
|
|
boolean stillFading = mVertScrollLayer.fade() | mHorizScrollLayer.fade();
|
|
|
|
if (stillFading) {
|
|
|
|
mFadeRunnable.scheduleNextFadeFrame();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mLastPageContext = mPageContext;
|
|
|
|
|
|
|
|
/* Update layers. */
|
2012-02-23 10:25:19 -08:00
|
|
|
if (rootLayer != null) mUpdated &= rootLayer.update(mPageContext); // called on compositor thread
|
|
|
|
mUpdated &= mBackgroundLayer.update(mScreenContext); // called on compositor thread
|
|
|
|
mUpdated &= mShadowLayer.update(mPageContext); // called on compositor thread
|
2012-04-24 12:13:36 -07:00
|
|
|
mUpdated &= mCheckerboardLayer.update(mPageContext); // called on compositor thread
|
2012-02-28 15:08:43 -08:00
|
|
|
if (mFrameRateLayer != null) mUpdated &= mFrameRateLayer.update(mScreenContext); // called on compositor thread
|
2012-02-23 10:25:19 -08:00
|
|
|
mUpdated &= mVertScrollLayer.update(mPageContext); // called on compositor thread
|
|
|
|
mUpdated &= mHorizScrollLayer.update(mPageContext); // called on compositor thread
|
2012-02-08 22:27:01 -08:00
|
|
|
|
|
|
|
for (Layer layer : mExtraLayers)
|
2012-02-23 10:25:19 -08:00
|
|
|
mUpdated &= layer.update(mPageContext); // called on compositor thread
|
2012-02-08 22:27:01 -08:00
|
|
|
}
|
|
|
|
|
2012-04-26 10:45:31 -07:00
|
|
|
/** Retrieves the bounds for the layer, rounded in such a way that it
|
|
|
|
* can be used as a mask for something that will render underneath it.
|
|
|
|
* This will round the bounds inwards, but stretch the mask towards any
|
|
|
|
* near page edge, where near is considered to be 'within 2 pixels'.
|
|
|
|
* Returns null if the given layer is null.
|
|
|
|
*/
|
|
|
|
private Rect getMaskForLayer(Layer layer) {
|
|
|
|
if (layer == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
RectF bounds = RectUtils.contract(layer.getBounds(mPageContext), 1.0f, 1.0f);
|
|
|
|
Rect mask = RectUtils.roundIn(bounds);
|
|
|
|
|
|
|
|
// If the mask is within two pixels of any page edge, stretch it over
|
|
|
|
// that edge. This is to avoid drawing thin slivers when masking
|
|
|
|
// layers.
|
|
|
|
if (mask.top <= 2) {
|
|
|
|
mask.top = -1;
|
|
|
|
}
|
|
|
|
if (mask.left <= 2) {
|
|
|
|
mask.left = -1;
|
|
|
|
}
|
2012-04-27 09:54:18 -07:00
|
|
|
|
|
|
|
// Because we're drawing relative to the page-rect, we only need to
|
|
|
|
// take into account its width and height (and not its origin)
|
|
|
|
int pageRight = mPageRect.width();
|
|
|
|
int pageBottom = mPageRect.height();
|
|
|
|
|
|
|
|
if (mask.right >= pageRight - 2) {
|
|
|
|
mask.right = pageRight + 1;
|
2012-04-26 10:45:31 -07:00
|
|
|
}
|
2012-04-27 09:54:18 -07:00
|
|
|
if (mask.bottom >= pageBottom - 2) {
|
|
|
|
mask.bottom = pageBottom + 1;
|
2012-04-26 10:45:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
2012-02-23 10:25:19 -08:00
|
|
|
/** This function is invoked via JNI; be careful when modifying signature. */
|
2012-02-08 22:27:01 -08:00
|
|
|
public void drawBackground() {
|
2012-05-01 09:12:45 -07:00
|
|
|
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
|
|
|
|
|
2012-04-27 09:54:18 -07:00
|
|
|
/* Update background color. */
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
mBackgroundColor = mView.getController().getCheckerboardColor();
|
2012-04-27 09:54:18 -07:00
|
|
|
|
|
|
|
/* Clear to the page background colour. The bits set here need to
|
|
|
|
* match up with those used in gfx/layers/opengl/LayerManagerOGL.cpp.
|
|
|
|
*/
|
|
|
|
GLES20.glClearColor(((mBackgroundColor>>16)&0xFF) / 255.0f,
|
|
|
|
((mBackgroundColor>>8)&0xFF) / 255.0f,
|
|
|
|
(mBackgroundColor&0xFF) / 255.0f,
|
|
|
|
0.0f);
|
|
|
|
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT |
|
|
|
|
GLES20.GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
2012-02-08 22:27:01 -08:00
|
|
|
/* Draw the background. */
|
2012-04-05 12:58:42 -07:00
|
|
|
mBackgroundLayer.setMask(mPageRect);
|
2012-02-08 22:27:01 -08:00
|
|
|
mBackgroundLayer.draw(mScreenContext);
|
|
|
|
|
|
|
|
/* Draw the drop shadow, if we need to. */
|
2012-04-05 12:58:42 -07:00
|
|
|
RectF untransformedPageRect = new RectF(0.0f, 0.0f, mPageRect.width(),
|
|
|
|
mPageRect.height());
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
if (!untransformedPageRect.contains(mView.getController().getViewport()))
|
2012-02-08 22:27:01 -08:00
|
|
|
mShadowLayer.draw(mPageContext);
|
|
|
|
|
2012-04-27 09:54:18 -07:00
|
|
|
/* Draw the 'checkerboard'. We use gfx.show_checkerboard_pattern to
|
|
|
|
* determine whether to draw the screenshot layer.
|
|
|
|
*/
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
if (mView.getController().checkerboardShouldShowChecks()) {
|
2012-04-27 09:54:18 -07:00
|
|
|
/* Find the area the root layer will render into, to mask the checkerboard layer */
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
Rect rootMask = getMaskForLayer(mView.getController().getRoot());
|
2012-04-27 09:54:18 -07:00
|
|
|
mCheckerboardLayer.setMask(rootMask);
|
|
|
|
|
|
|
|
/* Scissor around the page-rect, in case the page has shrunk
|
|
|
|
* since the screenshot layer was last updated.
|
|
|
|
*/
|
2012-05-01 09:12:45 -07:00
|
|
|
setScissorRect(); // Calls glEnable(GL_SCISSOR_TEST))
|
2012-04-27 09:54:18 -07:00
|
|
|
mCheckerboardLayer.draw(mPageContext);
|
|
|
|
}
|
2012-02-08 22:27:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Draws the layer the client added to us.
|
2012-02-09 22:58:18 -08:00
|
|
|
void drawRootLayer() {
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
Layer rootLayer = mView.getController().getRoot();
|
2012-02-13 20:20:38 -08:00
|
|
|
if (rootLayer == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rootLayer.draw(mPageContext);
|
2012-02-08 22:27:01 -08:00
|
|
|
}
|
|
|
|
|
2012-02-23 10:25:19 -08:00
|
|
|
/** This function is invoked via JNI; be careful when modifying signature. */
|
2012-02-08 22:27:01 -08:00
|
|
|
public void drawForeground() {
|
|
|
|
/* Draw any extra layers that were added (likely plugins) */
|
2012-03-12 10:03:54 -07:00
|
|
|
if (mExtraLayers.size() > 0) {
|
2012-04-27 13:04:47 -07:00
|
|
|
for (Layer layer : mExtraLayers) {
|
|
|
|
if (!layer.usesDefaultProgram())
|
|
|
|
deactivateDefaultProgram();
|
|
|
|
|
2012-03-12 10:03:54 -07:00
|
|
|
layer.draw(mPageContext);
|
|
|
|
|
2012-04-27 13:04:47 -07:00
|
|
|
if (!layer.usesDefaultProgram())
|
|
|
|
activateDefaultProgram();
|
|
|
|
}
|
2012-03-12 10:03:54 -07:00
|
|
|
}
|
2012-02-08 22:27:01 -08:00
|
|
|
|
|
|
|
/* Draw the vertical scrollbar. */
|
2012-04-17 22:34:05 -07:00
|
|
|
if (mPageRect.height() > mFrameMetrics.getHeight())
|
2012-02-08 22:27:01 -08:00
|
|
|
mVertScrollLayer.draw(mPageContext);
|
|
|
|
|
|
|
|
/* Draw the horizontal scrollbar. */
|
2012-04-17 22:34:05 -07:00
|
|
|
if (mPageRect.width() > mFrameMetrics.getWidth())
|
2012-02-08 22:27:01 -08:00
|
|
|
mHorizScrollLayer.draw(mPageContext);
|
|
|
|
|
|
|
|
/* Measure how much of the screen is checkerboarding */
|
Backout d2ee4c12c0b3 (bug 777351), 5aa6f94160dd (bug 777351), b47c470168fc (bug 777351), 5fb303ba52f7 (bug 777351), be81e4c3d928 (bug 777351), abc5b9a922dc (bug 777075), 8f1fc980f1f1 (bug 777075), 0b194a7f47d4 (bug 777075), d10df9bfef60 (bug 777075), 65393fe32cce (bug 777075), b52dc1df2fde (bug 777075), 8aeda525c094 (bug 777075) for Android native R1 failures on a CLOSED TREE
2012-08-01 10:42:05 -07:00
|
|
|
Layer rootLayer = mView.getController().getRoot();
|
2012-02-08 22:27:01 -08:00
|
|
|
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);
|
2012-04-24 08:26:21 -07:00
|
|
|
|
|
|
|
/* restrict the viewport to page bounds so we don't
|
|
|
|
* count overscroll as checkerboard */
|
2012-06-06 06:56:48 -07:00
|
|
|
if (!viewport.intersect(mPageRect)) {
|
2012-04-24 08:26:21 -07:00
|
|
|
/* if the rectangles don't intersect
|
|
|
|
intersect() doesn't change viewport
|
|
|
|
so we set it to empty by hand */
|
|
|
|
viewport.setEmpty();
|
|
|
|
}
|
2012-02-08 22:27:01 -08:00
|
|
|
validRegion.op(viewport, Region.Op.INTERSECT);
|
|
|
|
|
|
|
|
float checkerboard = 0.0f;
|
2012-04-26 11:23:28 -07:00
|
|
|
|
|
|
|
int screenArea = viewport.width() * viewport.height();
|
|
|
|
if (screenArea > 0 && !(validRegion.isRect() && validRegion.getBounds().equals(viewport))) {
|
2012-02-08 22:27:01 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
PanningPerfAPI.recordCheckerboard(checkerboard);
|
|
|
|
|
|
|
|
mCompleteFramesRendered += 1.0f - checkerboard;
|
|
|
|
mFramesRendered ++;
|
|
|
|
|
|
|
|
if (mFrameStartTime - mProfileOutputTime > 1000) {
|
|
|
|
mProfileOutputTime = mFrameStartTime;
|
|
|
|
printCheckerboardStats();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Draw the FPS. */
|
2012-02-28 15:08:43 -08:00
|
|
|
if (mFrameRateLayer != null) {
|
2012-02-08 22:27:01 -08:00
|
|
|
updateDroppedFrames(mFrameStartTime);
|
|
|
|
|
2012-02-23 08:31:01 -08:00
|
|
|
GLES20.glEnable(GLES20.GL_BLEND);
|
|
|
|
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
mFrameRateLayer.draw(mScreenContext);
|
2012-02-08 22:27:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-23 10:25:19 -08:00
|
|
|
/** This function is invoked via JNI; be careful when modifying signature. */
|
2012-02-08 22:27:01 -08:00
|
|
|
public void endDrawing() {
|
|
|
|
// If a layer update requires further work, schedule another redraw
|
|
|
|
if (!mUpdated)
|
|
|
|
mView.requestRender();
|
|
|
|
|
|
|
|
PanningPerfAPI.recordFrameTime();
|
|
|
|
|
|
|
|
/* Used by robocop for testing purposes */
|
|
|
|
IntBuffer pixelBuffer = mPixelBuffer;
|
|
|
|
if (mUpdated && pixelBuffer != null) {
|
|
|
|
synchronized (pixelBuffer) {
|
|
|
|
pixelBuffer.position(0);
|
|
|
|
GLES20.glReadPixels(0, 0, (int)mScreenContext.viewport.width(),
|
|
|
|
(int)mScreenContext.viewport.height(), GLES20.GL_RGBA,
|
|
|
|
GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
|
|
|
|
pixelBuffer.notify();
|
|
|
|
}
|
|
|
|
}
|
2012-03-22 15:07:00 -07:00
|
|
|
|
|
|
|
// Remove white screen once we've painted
|
|
|
|
if (mView.getPaintState() == LayerView.PAINT_BEFORE_FIRST) {
|
|
|
|
GeckoAppShell.getMainHandler().postAtFrontOfQueue(new Runnable() {
|
|
|
|
public void run() {
|
|
|
|
mView.setBackgroundColor(android.graphics.Color.TRANSPARENT);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
mView.setPaintState(LayerView.PAINT_AFTER_FIRST);
|
|
|
|
}
|
2012-02-08 22:27:01 -08:00
|
|
|
}
|
|
|
|
}
|
2011-12-09 07:01:28 -08:00
|
|
|
}
|