Enable debug stuffs
Bug: 14596762 * dumpsys gfxinfo implemented * profile GPU visual_bars implemented Change-Id: Icb948a9d5af5989b5615504d0d76ade64b93ef5b
This commit is contained in:
@@ -61,6 +61,7 @@ import android.view.Surface.OutOfResourcesException;
|
||||
|
||||
import com.google.android.gles_jni.EGLImpl;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -106,7 +107,6 @@ public class GLRenderer extends HardwareRenderer {
|
||||
|
||||
private static final String[] VISUALIZERS = {
|
||||
PROFILE_PROPERTY_VISUALIZE_BARS,
|
||||
PROFILE_PROPERTY_VISUALIZE_LINES
|
||||
};
|
||||
|
||||
private static final String[] OVERDRAW = {
|
||||
@@ -674,7 +674,7 @@ public class GLRenderer extends HardwareRenderer {
|
||||
mProfilePaint = null;
|
||||
|
||||
if (value) {
|
||||
mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
|
||||
mDebugDataProvider = new GraphDataProvider(graphType);
|
||||
} else {
|
||||
mDebugDataProvider = null;
|
||||
}
|
||||
@@ -742,7 +742,7 @@ public class GLRenderer extends HardwareRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
void dumpGfxInfo(PrintWriter pw) {
|
||||
void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
|
||||
if (mProfileEnabled) {
|
||||
pw.printf("\n\tDraw\tProcess\tExecute\n");
|
||||
|
||||
@@ -763,11 +763,6 @@ public class GLRenderer extends HardwareRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
long getFrameCount() {
|
||||
return mFrameCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this renderer instance can track and update dirty regions.
|
||||
*/
|
||||
@@ -1446,7 +1441,18 @@ public class GLRenderer extends HardwareRenderer {
|
||||
|
||||
private static native void nPrepareTree(long displayListPtr);
|
||||
|
||||
class DrawPerformanceDataProvider extends GraphDataProvider {
|
||||
class GraphDataProvider {
|
||||
/**
|
||||
* Draws the graph as bars. Frame elements are stacked on top of
|
||||
* each other.
|
||||
*/
|
||||
public static final int GRAPH_TYPE_BARS = 0;
|
||||
/**
|
||||
* Draws the graph as lines. The number of series drawn corresponds
|
||||
* to the number of elements.
|
||||
*/
|
||||
public static final int GRAPH_TYPE_LINES = 1;
|
||||
|
||||
private final int mGraphType;
|
||||
|
||||
private int mVerticalUnit;
|
||||
@@ -1454,11 +1460,10 @@ public class GLRenderer extends HardwareRenderer {
|
||||
private int mHorizontalMargin;
|
||||
private int mThresholdStroke;
|
||||
|
||||
DrawPerformanceDataProvider(int graphType) {
|
||||
public GraphDataProvider(int graphType) {
|
||||
mGraphType = graphType;
|
||||
}
|
||||
|
||||
@Override
|
||||
void prepare(DisplayMetrics metrics) {
|
||||
final float density = metrics.density;
|
||||
|
||||
@@ -1468,64 +1473,52 @@ public class GLRenderer extends HardwareRenderer {
|
||||
mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
|
||||
}
|
||||
|
||||
@Override
|
||||
int getGraphType() {
|
||||
return mGraphType;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getVerticalUnitSize() {
|
||||
return mVerticalUnit;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getHorizontalUnitSize() {
|
||||
return mHorizontalUnit;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getHorizontaUnitMargin() {
|
||||
return mHorizontalMargin;
|
||||
}
|
||||
|
||||
@Override
|
||||
float[] getData() {
|
||||
return mProfileData;
|
||||
}
|
||||
|
||||
@Override
|
||||
float getThreshold() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getFrameCount() {
|
||||
return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getElementCount() {
|
||||
return PROFILE_FRAME_DATA_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getCurrentFrame() {
|
||||
return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
void setupGraphPaint(Paint paint, int elementIndex) {
|
||||
paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
|
||||
if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setupThresholdPaint(Paint paint) {
|
||||
paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
|
||||
paint.setStrokeWidth(mThresholdStroke);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setupCurrentFramePaint(Paint paint) {
|
||||
paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
|
||||
if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
package android.view;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Surface.OutOfResourcesException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
@@ -61,11 +61,9 @@ public abstract class HardwareRenderer {
|
||||
* Possible values:
|
||||
* "true", to enable profiling
|
||||
* "visual_bars", to enable profiling and visualize the results on screen
|
||||
* "visual_lines", to enable profiling and visualize the results on screen
|
||||
* "false", to disable profiling
|
||||
*
|
||||
* @see #PROFILE_PROPERTY_VISUALIZE_BARS
|
||||
* @see #PROFILE_PROPERTY_VISUALIZE_LINES
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -79,14 +77,6 @@ public abstract class HardwareRenderer {
|
||||
*/
|
||||
public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars";
|
||||
|
||||
/**
|
||||
* Value for {@link #PROFILE_PROPERTY}. When the property is set to this
|
||||
* value, profiling data will be visualized on screen as a line chart.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String PROFILE_PROPERTY_VISUALIZE_LINES = "visual_lines";
|
||||
|
||||
/**
|
||||
* System property used to specify the number of frames to be used
|
||||
* when doing hardware rendering profiling.
|
||||
@@ -298,16 +288,8 @@ public abstract class HardwareRenderer {
|
||||
|
||||
/**
|
||||
* Outputs extra debugging information in the specified file descriptor.
|
||||
* @param pw
|
||||
*/
|
||||
abstract void dumpGfxInfo(PrintWriter pw);
|
||||
|
||||
/**
|
||||
* Outputs the total number of frames rendered (used for fps calculations)
|
||||
*
|
||||
* @return the number of frames rendered
|
||||
*/
|
||||
abstract long getFrameCount();
|
||||
abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd);
|
||||
|
||||
/**
|
||||
* Loads system properties used by the renderer. This method is invoked
|
||||
@@ -583,98 +565,4 @@ public abstract class HardwareRenderer {
|
||||
*/
|
||||
public void notifyFramePending() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a series of frames that should be drawn on screen as a graph.
|
||||
* Each frame is composed of 1 or more elements.
|
||||
*/
|
||||
abstract class GraphDataProvider {
|
||||
/**
|
||||
* Draws the graph as bars. Frame elements are stacked on top of
|
||||
* each other.
|
||||
*/
|
||||
public static final int GRAPH_TYPE_BARS = 0;
|
||||
/**
|
||||
* Draws the graph as lines. The number of series drawn corresponds
|
||||
* to the number of elements.
|
||||
*/
|
||||
public static final int GRAPH_TYPE_LINES = 1;
|
||||
|
||||
/**
|
||||
* Returns the type of graph to render.
|
||||
*
|
||||
* @return {@link #GRAPH_TYPE_BARS} or {@link #GRAPH_TYPE_LINES}
|
||||
*/
|
||||
abstract int getGraphType();
|
||||
|
||||
/**
|
||||
* This method is invoked before the graph is drawn. This method
|
||||
* can be used to compute sizes, etc.
|
||||
*
|
||||
* @param metrics The display metrics
|
||||
*/
|
||||
abstract void prepare(DisplayMetrics metrics);
|
||||
|
||||
/**
|
||||
* @return The size in pixels of a vertical unit.
|
||||
*/
|
||||
abstract int getVerticalUnitSize();
|
||||
|
||||
/**
|
||||
* @return The size in pixels of a horizontal unit.
|
||||
*/
|
||||
abstract int getHorizontalUnitSize();
|
||||
|
||||
/**
|
||||
* @return The size in pixels of the margin between horizontal units.
|
||||
*/
|
||||
abstract int getHorizontaUnitMargin();
|
||||
|
||||
/**
|
||||
* An optional threshold value.
|
||||
*
|
||||
* @return A value >= 0 to draw the threshold, a negative value
|
||||
* to ignore it.
|
||||
*/
|
||||
abstract float getThreshold();
|
||||
|
||||
/**
|
||||
* The data to draw in the graph. The number of elements in the
|
||||
* array must be at least {@link #getFrameCount()} * {@link #getElementCount()}.
|
||||
* If a value is negative the following values will be ignored.
|
||||
*/
|
||||
abstract float[] getData();
|
||||
|
||||
/**
|
||||
* Returns the number of frames to render in the graph.
|
||||
*/
|
||||
abstract int getFrameCount();
|
||||
|
||||
/**
|
||||
* Returns the number of elements in each frame. This directly affects
|
||||
* the number of series drawn in the graph.
|
||||
*/
|
||||
abstract int getElementCount();
|
||||
|
||||
/**
|
||||
* Returns the current frame, if any. If the returned value is negative
|
||||
* the current frame is ignored.
|
||||
*/
|
||||
abstract int getCurrentFrame();
|
||||
|
||||
/**
|
||||
* Prepares the paint to draw the specified element (or series.)
|
||||
*/
|
||||
abstract void setupGraphPaint(Paint paint, int elementIndex);
|
||||
|
||||
/**
|
||||
* Prepares the paint to draw the threshold.
|
||||
*/
|
||||
abstract void setupThresholdPaint(Paint paint);
|
||||
|
||||
/**
|
||||
* Prepares the paint to draw the current frame indicator.
|
||||
*/
|
||||
abstract void setupCurrentFramePaint(Paint paint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,6 +850,13 @@ public class RenderNode {
|
||||
nOutput(mNativeRenderNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the DisplayList for debug purposes.
|
||||
*/
|
||||
public int getDebugSize() {
|
||||
return nGetDebugSize(mNativeRenderNode);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Animations
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -941,6 +948,7 @@ public class RenderNode {
|
||||
private static native float nGetPivotX(long renderNode);
|
||||
private static native float nGetPivotY(long renderNode);
|
||||
private static native void nOutput(long renderNode);
|
||||
private static native int nGetDebugSize(long renderNode);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Animations
|
||||
|
||||
@@ -22,12 +22,14 @@ import android.graphics.SurfaceTexture;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.Trace;
|
||||
import android.util.Log;
|
||||
import android.util.TimeUtils;
|
||||
import android.view.Surface.OutOfResourcesException;
|
||||
import android.view.View.AttachInfo;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
@@ -60,11 +62,16 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
// Needs a ViewRoot invalidate
|
||||
private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
|
||||
|
||||
private static final String[] VISUALIZERS = {
|
||||
PROFILE_PROPERTY_VISUALIZE_BARS,
|
||||
};
|
||||
|
||||
private int mWidth, mHeight;
|
||||
private long mNativeProxy;
|
||||
private boolean mInitialized = false;
|
||||
private RenderNode mRootNode;
|
||||
private Choreographer mChoreographer;
|
||||
private boolean mProfilingEnabled;
|
||||
|
||||
ThreadedRenderer(boolean translucent) {
|
||||
AtlasInitializer.sInstance.init();
|
||||
@@ -77,6 +84,8 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
// Setup timing
|
||||
mChoreographer = Choreographer.getInstance();
|
||||
nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
|
||||
|
||||
loadSystemProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -166,19 +175,33 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
void dumpGfxInfo(PrintWriter pw) {
|
||||
// TODO Auto-generated method stub
|
||||
void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
|
||||
pw.flush();
|
||||
nDumpProfileInfo(mNativeProxy, fd);
|
||||
}
|
||||
|
||||
@Override
|
||||
long getFrameCount() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
private static int search(String[] values, String value) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (values[i].equals(value)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static boolean checkIfProfilingRequested() {
|
||||
String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
|
||||
int graphType = search(VISUALIZERS, profiling);
|
||||
return (graphType >= 0) || Boolean.parseBoolean(profiling);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean loadSystemProperties() {
|
||||
return nLoadSystemProperties(mNativeProxy);
|
||||
boolean changed = nLoadSystemProperties(mNativeProxy);
|
||||
boolean wantProfiling = checkIfProfilingRequested();
|
||||
if (wantProfiling != mProfilingEnabled) {
|
||||
mProfilingEnabled = wantProfiling;
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
|
||||
@@ -210,14 +233,24 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
long frameTimeNanos = mChoreographer.getFrameTimeNanos();
|
||||
attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
|
||||
|
||||
long recordDuration = 0;
|
||||
if (mProfilingEnabled) {
|
||||
recordDuration = System.nanoTime();
|
||||
}
|
||||
|
||||
updateRootDisplayList(view, callbacks);
|
||||
|
||||
if (mProfilingEnabled) {
|
||||
recordDuration = System.nanoTime() - recordDuration;
|
||||
}
|
||||
|
||||
attachInfo.mIgnoreDirtyState = false;
|
||||
|
||||
if (dirty == null) {
|
||||
dirty = NULL_RECT;
|
||||
}
|
||||
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
|
||||
recordDuration, view.getResources().getDisplayMetrics().density,
|
||||
dirty.left, dirty.top, dirty.right, dirty.bottom);
|
||||
if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
|
||||
attachInfo.mViewRootImpl.invalidate();
|
||||
@@ -354,7 +387,8 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
private static native void nSetup(long nativeProxy, int width, int height,
|
||||
float lightX, float lightY, float lightZ, float lightRadius);
|
||||
private static native void nSetOpaque(long nativeProxy, boolean opaque);
|
||||
private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
|
||||
private static native int nSyncAndDrawFrame(long nativeProxy,
|
||||
long frameTimeNanos, long recordDuration, float density,
|
||||
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
|
||||
private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
|
||||
private static native void nDestroyCanvasAndSurface(long nativeProxy);
|
||||
@@ -370,4 +404,6 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
|
||||
private static native void nFence(long nativeProxy);
|
||||
private static native void nNotifyFramePending(long nativeProxy);
|
||||
|
||||
private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
|
||||
}
|
||||
|
||||
@@ -5329,7 +5329,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
RenderNode renderNode = view.mRenderNode;
|
||||
info[0]++;
|
||||
if (renderNode != null) {
|
||||
info[1] += 0; /* TODO: Memory used by RenderNodes (properties + DisplayLists) */
|
||||
info[1] += renderNode.getDebugSize();
|
||||
}
|
||||
|
||||
if (view instanceof ViewGroup) {
|
||||
|
||||
@@ -430,7 +430,7 @@ public final class WindowManagerGlobal {
|
||||
HardwareRenderer renderer =
|
||||
root.getView().mAttachInfo.mHardwareRenderer;
|
||||
if (renderer != null) {
|
||||
renderer.dumpGfxInfo(pw);
|
||||
renderer.dumpGfxInfo(pw, fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,11 +447,6 @@ public final class WindowManagerGlobal {
|
||||
String name = getWindowName(root);
|
||||
pw.printf(" %s\n %d views, %.2f kB of display lists",
|
||||
name, info[0], info[1] / 1024.0f);
|
||||
HardwareRenderer renderer =
|
||||
root.getView().mAttachInfo.mHardwareRenderer;
|
||||
if (renderer != null) {
|
||||
pw.printf(", %d frames rendered", renderer.getFrameCount());
|
||||
}
|
||||
pw.printf("\n\n");
|
||||
|
||||
viewsCount += info[0];
|
||||
|
||||
@@ -48,6 +48,12 @@ static void android_view_RenderNode_output(JNIEnv* env,
|
||||
renderNode->output();
|
||||
}
|
||||
|
||||
static jint android_view_RenderNode_getDebugSize(JNIEnv* env,
|
||||
jobject clazz, jlong renderNodePtr) {
|
||||
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
|
||||
return renderNode->getDebugSize();
|
||||
}
|
||||
|
||||
static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz, jstring name) {
|
||||
RenderNode* renderNode = new RenderNode();
|
||||
renderNode->incStrong(0);
|
||||
@@ -505,6 +511,7 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nDestroyRenderNode", "(J)V", (void*) android_view_RenderNode_destroyRenderNode },
|
||||
{ "nSetDisplayListData", "(JJ)V", (void*) android_view_RenderNode_setDisplayListData },
|
||||
{ "nOutput", "(J)V", (void*) android_view_RenderNode_output },
|
||||
{ "nGetDebugSize", "(J)I", (void*) android_view_RenderNode_getDebugSize },
|
||||
|
||||
{ "nSetCaching", "(JZ)V", (void*) android_view_RenderNode_setCaching },
|
||||
{ "nSetStaticMatrix", "(JJ)V", (void*) android_view_RenderNode_setStaticMatrix },
|
||||
|
||||
@@ -238,10 +238,11 @@ static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
|
||||
}
|
||||
|
||||
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
|
||||
jlong proxyPtr, jlong frameTimeNanos, jint dirtyLeft, jint dirtyTop,
|
||||
jint dirtyRight, jint dirtyBottom) {
|
||||
jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density,
|
||||
jint dirtyLeft, jint dirtyTop, jint dirtyRight, jint dirtyBottom) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
|
||||
return proxy->syncAndDrawFrame(frameTimeNanos, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
|
||||
return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density,
|
||||
dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
|
||||
}
|
||||
|
||||
static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
|
||||
@@ -311,6 +312,13 @@ static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobjec
|
||||
proxy->notifyFramePending();
|
||||
}
|
||||
|
||||
static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
|
||||
jlong proxyPtr, jobject javaFileDescriptor) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
|
||||
int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
|
||||
proxy->dumpProfileInfo(fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -332,7 +340,7 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
|
||||
{ "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup },
|
||||
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
|
||||
{ "nSyncAndDrawFrame", "(JJIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
|
||||
{ "nSyncAndDrawFrame", "(JJJFIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
|
||||
{ "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
|
||||
{ "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
|
||||
{ "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
|
||||
@@ -343,6 +351,7 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nFlushCaches", "(JI)V", (void*) android_view_ThreadedRenderer_flushCaches },
|
||||
{ "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
|
||||
{ "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
|
||||
{ "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
||||
DisplayListLogBuffer.cpp \
|
||||
DisplayListRenderer.cpp \
|
||||
Dither.cpp \
|
||||
DrawProfiler.cpp \
|
||||
Extensions.cpp \
|
||||
FboCache.cpp \
|
||||
GradientCache.cpp \
|
||||
|
||||
261
libs/hwui/DrawProfiler.cpp
Normal file
261
libs/hwui/DrawProfiler.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "DrawProfiler.h"
|
||||
|
||||
#include <cutils/compiler.h>
|
||||
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "Properties.h"
|
||||
|
||||
#define DEFAULT_MAX_FRAMES 128
|
||||
|
||||
#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == kNone)) return
|
||||
|
||||
#define NANOS_TO_MILLIS_FLOAT(nanos) ((nanos) * 0.000001f)
|
||||
|
||||
#define PROFILE_DRAW_WIDTH 3
|
||||
#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
|
||||
#define PROFILE_DRAW_DP_PER_MS 7
|
||||
|
||||
// Number of floats we want to display from FrameTimingData
|
||||
// If this is changed make sure to update the indexes below
|
||||
#define NUM_ELEMENTS 4
|
||||
|
||||
#define RECORD_INDEX 0
|
||||
#define PREPARE_INDEX 1
|
||||
#define PLAYBACK_INDEX 2
|
||||
#define SWAPBUFFERS_INDEX 3
|
||||
|
||||
// Must be NUM_ELEMENTS in size
|
||||
static const SkColor ELEMENT_COLORS[] = { 0xcf3e66cc, 0xcf8f00ff, 0xcfdc3912, 0xcfe69800 };
|
||||
static const SkColor CURRENT_FRAME_COLOR = 0xcf5faa4d;
|
||||
static const SkColor THRESHOLD_COLOR = 0xff5faa4d;
|
||||
|
||||
// We could get this from TimeLord and use the actual frame interval, but
|
||||
// this is good enough
|
||||
#define FRAME_THRESHOLD 16
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
static int dpToPx(int dp, float density) {
|
||||
return (int) (dp * density + 0.5f);
|
||||
}
|
||||
|
||||
DrawProfiler::DrawProfiler()
|
||||
: mType(kNone)
|
||||
, mDensity(0)
|
||||
, mData(NULL)
|
||||
, mDataSize(0)
|
||||
, mCurrentFrame(-1)
|
||||
, mPreviousTime(0)
|
||||
, mVerticalUnit(0)
|
||||
, mHorizontalUnit(0)
|
||||
, mThresholdStroke(0) {
|
||||
setDensity(1);
|
||||
}
|
||||
|
||||
DrawProfiler::~DrawProfiler() {
|
||||
destroyData();
|
||||
}
|
||||
|
||||
void DrawProfiler::setDensity(float density) {
|
||||
if (CC_UNLIKELY(mDensity != density)) {
|
||||
mDensity = density;
|
||||
mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
|
||||
mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
|
||||
mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawProfiler::startFrame(nsecs_t recordDurationNanos) {
|
||||
RETURN_IF_DISABLED();
|
||||
mData[mCurrentFrame].record = NANOS_TO_MILLIS_FLOAT(recordDurationNanos);
|
||||
mPreviousTime = systemTime(CLOCK_MONOTONIC);
|
||||
}
|
||||
|
||||
void DrawProfiler::markPlaybackStart() {
|
||||
RETURN_IF_DISABLED();
|
||||
nsecs_t now = systemTime(CLOCK_MONOTONIC);
|
||||
mData[mCurrentFrame].prepare = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime);
|
||||
mPreviousTime = now;
|
||||
}
|
||||
|
||||
void DrawProfiler::markPlaybackEnd() {
|
||||
RETURN_IF_DISABLED();
|
||||
nsecs_t now = systemTime(CLOCK_MONOTONIC);
|
||||
mData[mCurrentFrame].playback = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime);
|
||||
mPreviousTime = now;
|
||||
}
|
||||
|
||||
void DrawProfiler::finishFrame() {
|
||||
RETURN_IF_DISABLED();
|
||||
nsecs_t now = systemTime(CLOCK_MONOTONIC);
|
||||
mData[mCurrentFrame].swapBuffers = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime);
|
||||
mPreviousTime = now;
|
||||
mCurrentFrame = (mCurrentFrame + 1) % mDataSize;
|
||||
}
|
||||
|
||||
void DrawProfiler::unionDirty(Rect* dirty) {
|
||||
RETURN_IF_DISABLED();
|
||||
// Not worth worrying about minimizing the dirty region for debugging, so just
|
||||
// dirty the entire viewport.
|
||||
if (dirty) {
|
||||
dirty->setEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawProfiler::draw(OpenGLRenderer* canvas) {
|
||||
if (CC_LIKELY(mType != kBars)) {
|
||||
return;
|
||||
}
|
||||
|
||||
prepareShapes(canvas->getViewportHeight());
|
||||
drawGraph(canvas);
|
||||
drawCurrentFrame(canvas);
|
||||
drawThreshold(canvas);
|
||||
}
|
||||
|
||||
void DrawProfiler::createData() {
|
||||
if (mData) return;
|
||||
|
||||
mDataSize = property_get_int32(PROPERTY_PROFILE_MAXFRAMES, DEFAULT_MAX_FRAMES);
|
||||
if (mDataSize <= 0) mDataSize = 1;
|
||||
if (mDataSize > 4096) mDataSize = 4096; // Reasonable maximum
|
||||
mData = (FrameTimingData*) calloc(mDataSize, sizeof(FrameTimingData));
|
||||
mRects = new float*[NUM_ELEMENTS];
|
||||
for (int i = 0; i < NUM_ELEMENTS; i++) {
|
||||
// 4 floats per rect
|
||||
mRects[i] = (float*) calloc(mDataSize, 4 * sizeof(float));
|
||||
}
|
||||
mCurrentFrame = 0;
|
||||
}
|
||||
|
||||
void DrawProfiler::destroyData() {
|
||||
delete mData;
|
||||
mData = NULL;
|
||||
}
|
||||
|
||||
void DrawProfiler::addRect(Rect& r, float data, float* shapeOutput) {
|
||||
r.top = r.bottom - (data * mVerticalUnit);
|
||||
shapeOutput[0] = r.left;
|
||||
shapeOutput[1] = r.top;
|
||||
shapeOutput[2] = r.right;
|
||||
shapeOutput[3] = r.bottom;
|
||||
r.bottom = r.top;
|
||||
}
|
||||
|
||||
void DrawProfiler::prepareShapes(const int baseline) {
|
||||
Rect r;
|
||||
r.right = mHorizontalUnit;
|
||||
for (int i = 0; i < mDataSize; i++) {
|
||||
const int shapeIndex = i * 4;
|
||||
r.bottom = baseline;
|
||||
addRect(r, mData[i].record, mRects[RECORD_INDEX] + shapeIndex);
|
||||
addRect(r, mData[i].prepare, mRects[PREPARE_INDEX] + shapeIndex);
|
||||
addRect(r, mData[i].playback, mRects[PLAYBACK_INDEX] + shapeIndex);
|
||||
addRect(r, mData[i].swapBuffers, mRects[SWAPBUFFERS_INDEX] + shapeIndex);
|
||||
r.translate(mHorizontalUnit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawProfiler::drawGraph(OpenGLRenderer* canvas) {
|
||||
SkPaint paint;
|
||||
for (int i = 0; i < NUM_ELEMENTS; i++) {
|
||||
paint.setColor(ELEMENT_COLORS[i]);
|
||||
canvas->drawRects(mRects[i], mDataSize * 4, &paint);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawProfiler::drawCurrentFrame(OpenGLRenderer* canvas) {
|
||||
// This draws a solid rect over the entirety of the current frame's shape
|
||||
// To do so we use the bottom of mRects[0] and the top of mRects[NUM_ELEMENTS-1]
|
||||
// which will therefore fully overlap the previously drawn rects
|
||||
SkPaint paint;
|
||||
paint.setColor(CURRENT_FRAME_COLOR);
|
||||
const int i = mCurrentFrame * 4;
|
||||
canvas->drawRect(mRects[0][i], mRects[NUM_ELEMENTS-1][i+1], mRects[0][i+2],
|
||||
mRects[0][i+3], &paint);
|
||||
}
|
||||
|
||||
void DrawProfiler::drawThreshold(OpenGLRenderer* canvas) {
|
||||
SkPaint paint;
|
||||
paint.setColor(THRESHOLD_COLOR);
|
||||
paint.setStrokeWidth(mThresholdStroke);
|
||||
|
||||
float pts[4];
|
||||
pts[0] = 0.0f;
|
||||
pts[1] = pts[3] = canvas->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
|
||||
pts[2] = canvas->getViewportWidth();
|
||||
canvas->drawLines(pts, 4, &paint);
|
||||
}
|
||||
|
||||
DrawProfiler::ProfileType DrawProfiler::loadRequestedProfileType() {
|
||||
ProfileType type = kNone;
|
||||
char buf[PROPERTY_VALUE_MAX] = {'\0',};
|
||||
if (property_get(PROPERTY_PROFILE, buf, "") > 0) {
|
||||
if (!strcmp(buf, PROPERTY_PROFILE_VISUALIZE_BARS)) {
|
||||
type = kBars;
|
||||
} else if (!strcmp(buf, "true")) {
|
||||
type = kConsole;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool DrawProfiler::loadSystemProperties() {
|
||||
ProfileType newType = loadRequestedProfileType();
|
||||
if (newType != mType) {
|
||||
mType = newType;
|
||||
if (mType == kNone) {
|
||||
destroyData();
|
||||
} else {
|
||||
createData();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DrawProfiler::dumpData(int fd) {
|
||||
RETURN_IF_DISABLED();
|
||||
|
||||
// This method logs the last N frames (where N is <= mDataSize) since the
|
||||
// last call to dumpData(). In other words if there's a dumpData(), draw frame,
|
||||
// dumpData(), the last dumpData() should only log 1 frame.
|
||||
|
||||
const FrameTimingData emptyData = {0, 0, 0, 0};
|
||||
|
||||
FILE *file = fdopen(fd, "a");
|
||||
fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
|
||||
|
||||
for (int frameOffset = 1; frameOffset <= mDataSize; frameOffset++) {
|
||||
int i = (mCurrentFrame + frameOffset) % mDataSize;
|
||||
if (!memcmp(mData + i, &emptyData, sizeof(FrameTimingData))) {
|
||||
continue;
|
||||
}
|
||||
fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
|
||||
mData[i].record, mData[i].prepare, mData[i].playback, mData[i].swapBuffers);
|
||||
}
|
||||
// reset the buffer
|
||||
memset(mData, 0, sizeof(FrameTimingData) * mDataSize);
|
||||
mCurrentFrame = 0;
|
||||
|
||||
fflush(file);
|
||||
}
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
96
libs/hwui/DrawProfiler.h
Normal file
96
libs/hwui/DrawProfiler.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef DRAWPROFILER_H
|
||||
#define DRAWPROFILER_H
|
||||
|
||||
#include <utils/Timers.h>
|
||||
#include "Rect.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class OpenGLRenderer;
|
||||
|
||||
class DrawProfiler {
|
||||
public:
|
||||
DrawProfiler();
|
||||
~DrawProfiler();
|
||||
|
||||
bool loadSystemProperties();
|
||||
void setDensity(float density);
|
||||
|
||||
void startFrame(nsecs_t recordDurationNanos = 0);
|
||||
void markPlaybackStart();
|
||||
void markPlaybackEnd();
|
||||
void finishFrame();
|
||||
|
||||
void unionDirty(Rect* dirty);
|
||||
void draw(OpenGLRenderer* canvas);
|
||||
|
||||
void dumpData(int fd);
|
||||
|
||||
private:
|
||||
enum ProfileType {
|
||||
kNone,
|
||||
kConsole,
|
||||
kBars,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float record;
|
||||
float prepare;
|
||||
float playback;
|
||||
float swapBuffers;
|
||||
} FrameTimingData;
|
||||
|
||||
void createData();
|
||||
void destroyData();
|
||||
|
||||
void addRect(Rect& r, float data, float* shapeOutput);
|
||||
void prepareShapes(const int baseline);
|
||||
void drawGraph(OpenGLRenderer* canvas);
|
||||
void drawCurrentFrame(OpenGLRenderer* canvas);
|
||||
void drawThreshold(OpenGLRenderer* canvas);
|
||||
|
||||
ProfileType loadRequestedProfileType();
|
||||
|
||||
ProfileType mType;
|
||||
float mDensity;
|
||||
|
||||
FrameTimingData* mData;
|
||||
int mDataSize;
|
||||
|
||||
int mCurrentFrame;
|
||||
nsecs_t mPreviousTime;
|
||||
|
||||
int mVerticalUnit;
|
||||
int mHorizontalUnit;
|
||||
int mThresholdStroke;
|
||||
|
||||
/*
|
||||
* mRects represents an array of rect shapes, divided into NUM_ELEMENTS
|
||||
* groups such that each group is drawn with the same paint.
|
||||
* For example mRects[0] is the array of rect floats suitable for
|
||||
* OpenGLRenderer:drawRects() that makes up all the FrameTimingData:record
|
||||
* information.
|
||||
*/
|
||||
float** mRects;
|
||||
};
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
#endif /* DRAWPROFILER_H */
|
||||
@@ -88,6 +88,36 @@ enum DebugLevel {
|
||||
*/
|
||||
#define PROPERTY_DEBUG_NV_PROFILING "debug.hwui.nv_profiling"
|
||||
|
||||
/**
|
||||
* System property used to enable or disable hardware rendering profiling.
|
||||
* The default value of this property is assumed to be false.
|
||||
*
|
||||
* When profiling is enabled, the adb shell dumpsys gfxinfo command will
|
||||
* output extra information about the time taken to execute by the last
|
||||
* frames.
|
||||
*
|
||||
* Possible values:
|
||||
* "true", to enable profiling
|
||||
* "visual_bars", to enable profiling and visualize the results on screen
|
||||
* "false", to disable profiling
|
||||
*/
|
||||
#define PROPERTY_PROFILE "debug.hwui.profile"
|
||||
#define PROPERTY_PROFILE_VISUALIZE_BARS "visual_bars"
|
||||
|
||||
/**
|
||||
* System property used to specify the number of frames to be used
|
||||
* when doing hardware rendering profiling.
|
||||
* The default value of this property is #PROFILE_MAX_FRAMES.
|
||||
*
|
||||
* When profiling is enabled, the adb shell dumpsys gfxinfo command will
|
||||
* output extra information about the time taken to execute by the last
|
||||
* frames.
|
||||
*
|
||||
* Possible values:
|
||||
* "60", to set the limit of frames to 60
|
||||
*/
|
||||
#define PROPERTY_PROFILE_MAXFRAMES "debug.hwui.profile.maxframes"
|
||||
|
||||
/**
|
||||
* Used to enable/disable non-rectangular clipping debugging.
|
||||
*
|
||||
|
||||
@@ -93,6 +93,17 @@ void RenderNode::output(uint32_t level) {
|
||||
ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
|
||||
}
|
||||
|
||||
int RenderNode::getDebugSize() {
|
||||
int size = sizeof(RenderNode);
|
||||
if (mStagingDisplayListData) {
|
||||
size += mStagingDisplayListData->allocator.usedSize();
|
||||
}
|
||||
if (mDisplayListData && mDisplayListData != mStagingDisplayListData) {
|
||||
size += mDisplayListData->allocator.usedSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void RenderNode::prepareTree(TreeInfo& info) {
|
||||
ATRACE_CALL();
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ public:
|
||||
void replayNodeInParent(ReplayStateStruct& replayStruct, const int level);
|
||||
|
||||
ANDROID_API void output(uint32_t level = 1);
|
||||
ANDROID_API int getDebugSize();
|
||||
|
||||
bool isRenderable() const {
|
||||
return mDisplayListData && mDisplayListData->hasDrawOps;
|
||||
|
||||
@@ -486,6 +486,8 @@ void CanvasContext::draw(Rect* dirty) {
|
||||
LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
|
||||
"drawDisplayList called on a context with no canvas or surface!");
|
||||
|
||||
profiler().markPlaybackStart();
|
||||
|
||||
EGLint width, height;
|
||||
mGlobalContext->beginFrame(mEglSurface, &width, &height);
|
||||
if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
|
||||
@@ -493,6 +495,8 @@ void CanvasContext::draw(Rect* dirty) {
|
||||
dirty = NULL;
|
||||
} else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
|
||||
dirty = NULL;
|
||||
} else {
|
||||
profiler().unionDirty(dirty);
|
||||
}
|
||||
|
||||
status_t status;
|
||||
@@ -506,14 +510,17 @@ void CanvasContext::draw(Rect* dirty) {
|
||||
Rect outBounds;
|
||||
status |= mCanvas->drawDisplayList(mRootRenderNode.get(), outBounds);
|
||||
|
||||
// TODO: Draw debug info
|
||||
// TODO: Performance tracking
|
||||
profiler().draw(mCanvas);
|
||||
|
||||
mCanvas->finish();
|
||||
|
||||
profiler().markPlaybackEnd();
|
||||
|
||||
if (status & DrawGlInfo::kStatusDrew) {
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
profiler().finishFrame();
|
||||
}
|
||||
|
||||
// Called by choreographer to do an RT-driven animation
|
||||
@@ -524,6 +531,8 @@ void CanvasContext::doFrame() {
|
||||
|
||||
ATRACE_CALL();
|
||||
|
||||
profiler().startFrame();
|
||||
|
||||
TreeInfo info;
|
||||
info.evaluateAnimations = true;
|
||||
info.performStagingPush = false;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <utils/Functor.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#include "../DrawProfiler.h"
|
||||
#include "../RenderNode.h"
|
||||
#include "RenderTask.h"
|
||||
#include "RenderThread.h"
|
||||
@@ -77,6 +78,8 @@ public:
|
||||
|
||||
void notifyFramePending();
|
||||
|
||||
DrawProfiler& profiler() { return mProfiler; }
|
||||
|
||||
private:
|
||||
friend class RegisterFrameCallbackTask;
|
||||
|
||||
@@ -100,6 +103,8 @@ private:
|
||||
bool mHaveNewSurface;
|
||||
|
||||
const sp<RenderNode> mRootRenderNode;
|
||||
|
||||
DrawProfiler mProfiler;
|
||||
};
|
||||
|
||||
} /* namespace renderthread */
|
||||
|
||||
@@ -34,6 +34,8 @@ DrawFrameTask::DrawFrameTask()
|
||||
: mRenderThread(NULL)
|
||||
, mContext(NULL)
|
||||
, mFrameTimeNanos(0)
|
||||
, mRecordDurationNanos(0)
|
||||
, mDensity(1.0f) // safe enough default
|
||||
, mSyncResult(kSync_OK) {
|
||||
}
|
||||
|
||||
@@ -64,15 +66,17 @@ void DrawFrameTask::setDirty(int left, int top, int right, int bottom) {
|
||||
mDirty.set(left, top, right, bottom);
|
||||
}
|
||||
|
||||
int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) {
|
||||
int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {
|
||||
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
|
||||
|
||||
mSyncResult = kSync_OK;
|
||||
mFrameTimeNanos = frameTimeNanos;
|
||||
mRecordDurationNanos = recordDurationNanos;
|
||||
postAndWait();
|
||||
|
||||
// Reset the single-frame data
|
||||
mFrameTimeNanos = 0;
|
||||
mRecordDurationNanos = 0;
|
||||
mDirty.setEmpty();
|
||||
|
||||
return mSyncResult;
|
||||
@@ -87,6 +91,9 @@ void DrawFrameTask::postAndWait() {
|
||||
void DrawFrameTask::run() {
|
||||
ATRACE_NAME("DrawFrame");
|
||||
|
||||
mContext->profiler().setDensity(mDensity);
|
||||
mContext->profiler().startFrame(mRecordDurationNanos);
|
||||
|
||||
bool canUnblockUiThread;
|
||||
bool canDrawThisFrame;
|
||||
{
|
||||
|
||||
@@ -60,7 +60,8 @@ public:
|
||||
void removeLayer(DeferredLayerUpdater* layer);
|
||||
|
||||
void setDirty(int left, int top, int right, int bottom);
|
||||
int drawFrame(nsecs_t frameTimeNanos);
|
||||
void setDensity(float density) { mDensity = density; }
|
||||
int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos);
|
||||
|
||||
virtual void run();
|
||||
|
||||
@@ -80,6 +81,8 @@ private:
|
||||
*********************************************/
|
||||
Rect mDirty;
|
||||
nsecs_t mFrameTimeNanos;
|
||||
nsecs_t mRecordDurationNanos;
|
||||
float mDensity;
|
||||
|
||||
int mSyncResult;
|
||||
|
||||
|
||||
@@ -99,16 +99,20 @@ void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
|
||||
post(task);
|
||||
}
|
||||
|
||||
CREATE_BRIDGE0(loadSystemProperties) {
|
||||
CREATE_BRIDGE1(loadSystemProperties, CanvasContext* context) {
|
||||
bool needsRedraw = false;
|
||||
if (Caches::hasInstance()) {
|
||||
needsRedraw = Caches::getInstance().initProperties();
|
||||
}
|
||||
if (args->context->profiler().loadSystemProperties()) {
|
||||
needsRedraw = true;
|
||||
}
|
||||
return (void*) needsRedraw;
|
||||
}
|
||||
|
||||
bool RenderProxy::loadSystemProperties() {
|
||||
SETUP_TASK(loadSystemProperties);
|
||||
args->context = mContext;
|
||||
return (bool) postAndWait(task);
|
||||
}
|
||||
|
||||
@@ -175,10 +179,11 @@ void RenderProxy::setOpaque(bool opaque) {
|
||||
post(task);
|
||||
}
|
||||
|
||||
int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos,
|
||||
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
|
||||
int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
|
||||
float density, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
|
||||
mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
|
||||
return mDrawFrameTask.drawFrame(frameTimeNanos);
|
||||
mDrawFrameTask.setDensity(density);
|
||||
return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
|
||||
}
|
||||
|
||||
CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) {
|
||||
@@ -315,6 +320,18 @@ void RenderProxy::notifyFramePending() {
|
||||
mRenderThread.queueAtFront(task);
|
||||
}
|
||||
|
||||
CREATE_BRIDGE2(dumpProfileInfo, CanvasContext* context, int fd) {
|
||||
args->context->profiler().dumpData(args->fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RenderProxy::dumpProfileInfo(int fd) {
|
||||
SETUP_TASK(dumpProfileInfo);
|
||||
args->context = mContext;
|
||||
args->fd = fd;
|
||||
postAndWait(task);
|
||||
}
|
||||
|
||||
void RenderProxy::post(RenderTask* task) {
|
||||
mRenderThread.queue(task);
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ public:
|
||||
ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
|
||||
ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
|
||||
ANDROID_API void setOpaque(bool opaque);
|
||||
ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos,
|
||||
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
|
||||
ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
|
||||
float density, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
|
||||
ANDROID_API void destroyCanvasAndSurface();
|
||||
|
||||
ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion);
|
||||
@@ -87,6 +87,8 @@ public:
|
||||
ANDROID_API void fence();
|
||||
ANDROID_API void notifyFramePending();
|
||||
|
||||
ANDROID_API void dumpProfileInfo(int fd);
|
||||
|
||||
private:
|
||||
RenderThread& mRenderThread;
|
||||
CanvasContext* mContext;
|
||||
|
||||
Reference in New Issue
Block a user