mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 717349 - Add optional render and checkerboarding profiling. r=kats
This adds checkerboard profiling to LayerRenderer, that can be enabled either by enabling debug logging of the "GeckoLayerRendererProf" tag, or via reflection using PanningPerfAPI.
This commit is contained in:
parent
674b523321
commit
926982757d
@ -41,6 +41,7 @@ package org.mozilla.gecko.gfx;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.util.Log;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
@ -105,6 +106,15 @@ public abstract class Layer {
|
||||
return new RectF(x, y, x + width, y + height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the region of the layer that is considered valid. The default
|
||||
* implementation of this will return the bounds of the layer, but this
|
||||
* may be overridden.
|
||||
*/
|
||||
public Region getValidRegion(RenderContext context) {
|
||||
return new Region(RectUtils.round(getBounds(context, new FloatSize(getSize()))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this before modifying the layer. Note that, for TileLayers, "modifying the layer"
|
||||
* includes altering the underlying CairoImage in any way. Thus you must call this function
|
||||
|
@ -55,6 +55,8 @@ import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.RegionIterator;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.SystemClock;
|
||||
import android.util.DisplayMetrics;
|
||||
@ -70,6 +72,7 @@ import java.util.ArrayList;
|
||||
*/
|
||||
public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
private static final String LOGTAG = "GeckoLayerRenderer";
|
||||
private static final String PROFTAG = "GeckoLayerRendererProf";
|
||||
|
||||
/*
|
||||
* The amount of time a frame is allowed to take to render before we declare it a dropped
|
||||
@ -99,6 +102,12 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
private int mCurrentFrame, mFrameTimingsSum, mDroppedFrames;
|
||||
private boolean mShowFrameRate;
|
||||
|
||||
// Render profiling output
|
||||
private int mFramesRendered;
|
||||
private float mCompleteFramesRendered;
|
||||
private boolean mProfileRender;
|
||||
private long mProfileOutputTime;
|
||||
|
||||
/* Used by robocop for testing purposes */
|
||||
private IntBuffer mPixelBuffer;
|
||||
|
||||
@ -147,7 +156,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
}
|
||||
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
checkFrameRateMonitorEnabled();
|
||||
checkMonitoringEnabled();
|
||||
|
||||
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
||||
gl.glDisable(GL10.GL_DITHER);
|
||||
@ -264,11 +273,50 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
/* Draw the horizontal scrollbar. */
|
||||
if (pageRect.width() > screenSize.width)
|
||||
mHorizScrollLayer.draw(pageContext);
|
||||
|
||||
/* Measure how much of the screen is checkerboarding */
|
||||
if ((rootLayer != null) &&
|
||||
(mProfileRender || PanningPerfAPI.isRecordingCheckerboard())) {
|
||||
// Find out how much of the viewport area is valid
|
||||
Rect viewport = RectUtils.round(pageContext.viewport);
|
||||
Region validRegion = rootLayer.getValidRegion(pageContext);
|
||||
validRegion.op(viewport, Region.Op.INTERSECT);
|
||||
|
||||
float checkerboard = 0.0f;
|
||||
if (!(validRegion.isRect() && validRegion.getBounds().equals(viewport))) {
|
||||
int screenArea = viewport.width() * viewport.height();
|
||||
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 (frameStartTime - mProfileOutputTime > 1000) {
|
||||
mProfileOutputTime = frameStartTime;
|
||||
printCheckerboardStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw the FPS. */
|
||||
if (mShowFrameRate) {
|
||||
updateDroppedFrames(frameStartTime);
|
||||
|
||||
try {
|
||||
gl.glEnable(GL10.GL_BLEND);
|
||||
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
|
||||
@ -295,6 +343,12 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
private void printCheckerboardStats() {
|
||||
Log.d(PROFTAG, "Frames rendered over last 1000ms: " + mCompleteFramesRendered + "/" + mFramesRendered);
|
||||
mFramesRendered = 0;
|
||||
mCompleteFramesRendered = 0;
|
||||
}
|
||||
|
||||
/** Used by robocop for testing purposes. Not for production use! */
|
||||
IntBuffer getPixels() {
|
||||
IntBuffer pixelBuffer = IntBuffer.allocate(mView.getWidth() * mView.getHeight());
|
||||
@ -382,7 +436,6 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
mCurrentFrame = (mCurrentFrame + 1) % mFrameTimings.length;
|
||||
|
||||
int averageTime = mFrameTimingsSum / mFrameTimings.length;
|
||||
|
||||
mFrameRateLayer.beginTransaction();
|
||||
try {
|
||||
mFrameRateLayer.setText(averageTime + " ms/" + mDroppedFrames);
|
||||
@ -403,7 +456,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkFrameRateMonitorEnabled() {
|
||||
private void checkMonitoringEnabled() {
|
||||
/* Do this I/O off the main thread to minimize its impact on startup time. */
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
@ -411,6 +464,7 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
Context context = mView.getContext();
|
||||
SharedPreferences preferences = context.getSharedPreferences("GeckoApp", 0);
|
||||
mShowFrameRate = preferences.getBoolean("showFrameRate", false);
|
||||
mProfileRender = Log.isLoggable(PROFTAG, Log.DEBUG);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
@ -438,6 +438,18 @@ public class MultiTileLayer extends Layer {
|
||||
mRenderOffset.set(offset.x, offset.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getValidRegion(RenderContext context) {
|
||||
Region validRegion = new Region();
|
||||
for (SubTile tile : mTiles) {
|
||||
if (tile.key == null || tile.getValidTextureArea().isEmpty())
|
||||
continue;
|
||||
validRegion.op(tile.getValidRegion(context), Region.Op.UNION);
|
||||
}
|
||||
|
||||
return validRegion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all sub-tiles. This should be called if the source backing
|
||||
* this layer has changed. This method is only valid inside a transaction.
|
||||
|
@ -20,6 +20,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kartikaya Gupta <kgupta@mozilla.com>
|
||||
* Chris Lord <chrislord.net@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -50,37 +51,75 @@ public class PanningPerfAPI {
|
||||
// to measure.
|
||||
private static final int EXPECTED_FRAME_COUNT = 2048;
|
||||
|
||||
private static boolean mRecording = false;
|
||||
private static boolean mRecordingFrames = false;
|
||||
private static List<Long> mFrameTimes;
|
||||
private static long mStartTime;
|
||||
private static long mFrameStartTime;
|
||||
|
||||
private static boolean mRecordingCheckerboard = false;
|
||||
private static List<Float> mCheckerboardAmounts;
|
||||
private static long mCheckerboardStartTime;
|
||||
|
||||
public static void startFrameTimeRecording() {
|
||||
if (mRecording) {
|
||||
if (mRecordingFrames) {
|
||||
Log.e(LOGTAG, "Error: startFrameTimeRecording() called while already recording!");
|
||||
return;
|
||||
}
|
||||
mRecording = true;
|
||||
mRecordingFrames = true;
|
||||
if (mFrameTimes == null) {
|
||||
mFrameTimes = new ArrayList<Long>(EXPECTED_FRAME_COUNT);
|
||||
} else {
|
||||
mFrameTimes.clear();
|
||||
}
|
||||
mStartTime = SystemClock.uptimeMillis();
|
||||
mFrameStartTime = SystemClock.uptimeMillis();
|
||||
}
|
||||
|
||||
public static List<Long> stopFrameTimeRecording() {
|
||||
if (!mRecording) {
|
||||
if (!mRecordingFrames) {
|
||||
Log.e(LOGTAG, "Error: stopFrameTimeRecording() called when not recording!");
|
||||
return null;
|
||||
}
|
||||
mRecording = false;
|
||||
mRecordingFrames = false;
|
||||
return mFrameTimes;
|
||||
}
|
||||
|
||||
public static void recordFrameTime() {
|
||||
// this will be called often, so try to make it as quick as possible
|
||||
if (mRecording) {
|
||||
mFrameTimes.add(SystemClock.uptimeMillis() - mStartTime);
|
||||
if (mRecordingFrames) {
|
||||
mFrameTimes.add(SystemClock.uptimeMillis() - mFrameStartTime);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isRecordingCheckerboard() {
|
||||
return mRecordingCheckerboard;
|
||||
}
|
||||
|
||||
public static void startCheckerboardRecording() {
|
||||
if (mRecordingCheckerboard) {
|
||||
Log.e(LOGTAG, "Error: startCheckerboardRecording() called while already recording!");
|
||||
return;
|
||||
}
|
||||
mRecordingCheckerboard = true;
|
||||
if (mCheckerboardAmounts == null) {
|
||||
mCheckerboardAmounts = new ArrayList<Float>(EXPECTED_FRAME_COUNT);
|
||||
} else {
|
||||
mCheckerboardAmounts.clear();
|
||||
}
|
||||
mCheckerboardStartTime = SystemClock.uptimeMillis();
|
||||
}
|
||||
|
||||
public static List<Float> stopCheckerboardRecording() {
|
||||
if (!mRecordingCheckerboard) {
|
||||
Log.e(LOGTAG, "Error: stopCheckerboardRecording() called when not recording!");
|
||||
return null;
|
||||
}
|
||||
mRecordingCheckerboard = false;
|
||||
return mCheckerboardAmounts;
|
||||
}
|
||||
|
||||
public static void recordCheckerboard(float amount) {
|
||||
// this will be called often, so try to make it as quick as possible
|
||||
if (mRecordingCheckerboard) {
|
||||
mCheckerboardAmounts.add(amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +37,10 @@
|
||||
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.opengl.GLES20;
|
||||
import android.util.Log;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
@ -149,6 +151,22 @@ public abstract class TileLayer extends Layer {
|
||||
return mValidTextureRect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getValidRegion(RenderContext context) {
|
||||
if (mValidTextureRect.isEmpty())
|
||||
return new Region();
|
||||
|
||||
Point origin = getOrigin();
|
||||
float scaleFactor = context.zoomFactor / getResolution();
|
||||
float x = (origin.x + mValidTextureRect.left) * scaleFactor;
|
||||
float y = (origin.y + mValidTextureRect.top) * scaleFactor;
|
||||
float width = mValidTextureRect.width() * scaleFactor;
|
||||
float height = mValidTextureRect.height() * scaleFactor;
|
||||
|
||||
return new Region(Math.round(x), Math.round(y),
|
||||
Math.round(x + width), Math.round(y + height));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean performUpdates(GL10 gl, RenderContext context) {
|
||||
super.performUpdates(gl, context);
|
||||
|
Loading…
Reference in New Issue
Block a user