Add ability for hierarchyviewer to output displaylist info

Clicking on a node in hierarchyviewer1 and hierarchyviewer2 and then
clicking the new "Dump DisplayList" button will cause the display
list for the selected node (including its children) to be output into
logcat.

Change-Id: Iad05f5f6cca0f8b465dccd962b501dc18fe6e053
This commit is contained in:
Chet Haase
2011-04-22 16:18:45 -07:00
parent 098b781699
commit ed30fd8e9a
10 changed files with 378 additions and 2 deletions

View File

@ -261,6 +261,13 @@ class GLES20Canvas extends HardwareCanvas {
private static native boolean nDrawDisplayList(int renderer, int displayList,
int width, int height, Rect dirty);
@Override
void outputDisplayList(DisplayList displayList) {
nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
}
private static native void nOutputDisplayList(int renderer, int displayList);
///////////////////////////////////////////////////////////////////////////
// Hardware layer
///////////////////////////////////////////////////////////////////////////

View File

@ -63,6 +63,14 @@ public abstract class HardwareCanvas extends Canvas {
*/
abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
/**
* Outputs the specified display list to the log. This method exists for use by
* tools to output display lists for selected nodes to the log.
*
* @param displayList The display list to be logged.
*/
abstract void outputDisplayList(DisplayList displayList);
/**
* Draws the specified layer onto this canvas.
*

View File

@ -1507,6 +1507,20 @@ public final class ViewAncestor extends Handler implements ViewParent,
}
}
/**
* @hide
*/
void outputDisplayList(View view) {
if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
HardwareCanvas canvas = (HardwareCanvas) mAttachInfo.mHardwareCanvas;
DisplayList displayList = view.getDisplayList();
if (displayList != null) {
canvas.outputDisplayList(displayList);
}
}
}
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (surface == null || !surface.isValid()) {

View File

@ -375,6 +375,7 @@ public class ViewDebug {
private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
private static final String REMOTE_PROFILE = "PROFILE";
private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS";
private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST";
private static HashMap<Class<?>, Field[]> sFieldsForClasses;
private static HashMap<Class<?>, Method[]> sMethodsForClasses;
@ -885,6 +886,8 @@ public class ViewDebug {
final String[] params = parameters.split(" ");
if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
capture(view, clientStream, params[0]);
} else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
outputDisplayList(view, params[0]);
} else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
invalidate(view, params[0]);
} else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
@ -1156,6 +1159,11 @@ public class ViewDebug {
}
}
private static void outputDisplayList(View root, String parameter) throws IOException {
final View view = findView(root, parameter);
view.getViewAncestor().outputDisplayList(view);
}
private static void capture(View root, final OutputStream clientStream, String parameter)
throws IOException {

View File

@ -519,6 +519,11 @@ static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
return redraw;
}
static void android_view_GLES20Canvas_outputDisplayList(JNIEnv* env,
jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
renderer->outputDisplayList(displayList);
}
// ----------------------------------------------------------------------------
// Layers
// ----------------------------------------------------------------------------
@ -714,7 +719,7 @@ static JNINativeMethod gMethods[] = {
{ "nGetDisplayListRenderer", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListRenderer },
{ "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_drawDisplayList },
{ "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList },
{ "nInterrupt", "(I)V", (void*) android_view_GLES20Canvas_interrupt },
{ "nResume", "(I)V", (void*) android_view_GLES20Canvas_resume },

View File

@ -177,6 +177,331 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
void DisplayList::init() {
}
/**
* This function is a simplified version of replay(), where we simply retrieve and log the
* display list. This function should remain in sync with the replay() function.
*/
void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
TextContainer text;
uint32_t count = (level + 1) * 2;
char indent[count + 1];
for (uint32_t i = 0; i < count; i++) {
indent[i] = ' ';
}
indent[count] = '\0';
LOGD("%sStart display list (%p)", (char*) indent + 2, this);
int saveCount = renderer.getSaveCount() - 1;
mReader.rewind();
while (!mReader.eof()) {
int op = mReader.readInt();
switch (op) {
case DrawGLFunction: {
Functor *functor = (Functor *) getInt();
LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
}
break;
case Save: {
int rendererNum = getInt();
LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
}
break;
case Restore: {
LOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
case RestoreToCount: {
int restoreCount = saveCount + getInt();
LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
}
break;
case SaveLayer: {
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
SkPaint* paint = getPaint();
int flags = getInt();
LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
OP_NAMES[op], f1, f2, f3, f4, paint, flags);
}
break;
case SaveLayerAlpha: {
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
int alpha = getInt();
int flags = getInt();
LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
}
break;
case Translate: {
float f1 = getFloat();
float f2 = getFloat();
LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
}
break;
case Rotate: {
float rotation = getFloat();
LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
}
break;
case Scale: {
float sx = getFloat();
float sy = getFloat();
LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
}
break;
case Skew: {
float sx = getFloat();
float sy = getFloat();
LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
}
break;
case SetMatrix: {
SkMatrix* matrix = getMatrix();
LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
}
break;
case ConcatMatrix: {
SkMatrix* matrix = getMatrix();
LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
}
break;
case ClipRect: {
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
int regionOp = getInt();
LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
f1, f2, f3, f4, regionOp);
}
break;
case DrawDisplayList: {
DisplayList* displayList = getDisplayList();
uint32_t width = getUInt();
uint32_t height = getUInt();
LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
displayList, width, height, level + 1);
renderer.outputDisplayList(displayList, level + 1);
}
break;
case DrawLayer: {
Layer* layer = (Layer*) getInt();
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint();
LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
layer, x, y, paint);
}
break;
case DrawBitmap: {
SkBitmap* bitmap = getBitmap();
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint();
LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
bitmap, x, y, paint);
}
break;
case DrawBitmapMatrix: {
SkBitmap* bitmap = getBitmap();
SkMatrix* matrix = getMatrix();
SkPaint* paint = getPaint();
LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
bitmap, matrix, paint);
}
break;
case DrawBitmapRect: {
SkBitmap* bitmap = getBitmap();
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
float f5 = getFloat();
float f6 = getFloat();
float f7 = getFloat();
float f8 = getFloat();
SkPaint* paint = getPaint();
LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
}
break;
case DrawBitmapMesh: {
int verticesCount = 0;
uint32_t colorsCount = 0;
SkBitmap* bitmap = getBitmap();
uint32_t meshWidth = getInt();
uint32_t meshHeight = getInt();
float* vertices = getFloats(verticesCount);
bool hasColors = getInt();
int* colors = hasColors ? getInts(colorsCount) : NULL;
SkPaint* paint = getPaint();
LOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
case DrawPatch: {
int32_t* xDivs = NULL;
int32_t* yDivs = NULL;
uint32_t* colors = NULL;
uint32_t xDivsCount = 0;
uint32_t yDivsCount = 0;
int8_t numColors = 0;
SkBitmap* bitmap = getBitmap();
xDivs = getInts(xDivsCount);
yDivs = getInts(yDivsCount);
colors = getUInts(numColors);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
getFloat();
getFloat();
getFloat();
getFloat();
getPaint();
}
break;
case DrawColor: {
int color = getInt();
int xferMode = getInt();
LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
}
break;
case DrawRect: {
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
SkPaint* paint = getPaint();
LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
f1, f2, f3, f4, paint);
}
break;
case DrawRoundRect: {
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
float f5 = getFloat();
float f6 = getFloat();
SkPaint* paint = getPaint();
LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
}
break;
case DrawCircle: {
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
SkPaint* paint = getPaint();
LOGD("%s%s %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, paint);
}
break;
case DrawOval: {
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
SkPaint* paint = getPaint();
LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
}
break;
case DrawArc: {
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
float f5 = getFloat();
float f6 = getFloat();
int i1 = getInt();
SkPaint* paint = getPaint();
LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
}
break;
case DrawPath: {
SkPath* path = getPath();
SkPaint* paint = getPaint();
LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
}
break;
case DrawLines: {
int count = 0;
float* points = getFloats(count);
SkPaint* paint = getPaint();
LOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
case DrawPoints: {
int count = 0;
float* points = getFloats(count);
SkPaint* paint = getPaint();
LOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
case DrawText: {
getText(&text);
int count = getInt();
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint();
LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
text.text(), text.length(), count, x, y, paint);
}
break;
case ResetShader: {
LOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
case SetupShader: {
SkiaShader* shader = getShader();
LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
}
break;
case ResetColorFilter: {
LOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
case SetupColorFilter: {
SkiaColorFilter *colorFilter = getColorFilter();
LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
}
break;
case ResetShadow: {
LOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
case SetupShadow: {
float radius = getFloat();
float dx = getFloat();
float dy = getFloat();
int color = getInt();
LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
radius, dx, dy, color);
}
break;
default:
LOGD("Display List error: op not handled: %s%s",
(char*) indent, OP_NAMES[op]);
break;
}
}
LOGD("%sDone", (char*) indent + 2);
}
/**
* Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
* in the output() function, since that function processes the same list of opcodes for the
* purposes of logging display list info for a given view.
*/
bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
bool needsInvalidate = false;
TextContainer text;

View File

@ -107,6 +107,8 @@ public:
bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
void output(OpenGLRenderer& renderer, uint32_t level = 0);
static void outputLogBuffer(int fd);
private:

View File

@ -1185,6 +1185,12 @@ bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, u
return false;
}
void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
if (displayList) {
displayList->output(*this, level);
}
}
void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
int alpha;
SkXfermode::Mode mode;

View File

@ -98,6 +98,7 @@ public:
virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
Rect& dirty, uint32_t level = 0);
virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);

View File

@ -49,7 +49,7 @@ class ViewServer implements Runnable {
// Debug facility
private static final String LOG_TAG = "ViewServer";
private static final String VALUE_PROTOCOL_VERSION = "3";
private static final String VALUE_PROTOCOL_VERSION = "4";
private static final String VALUE_SERVER_VERSION = "4";
// Protocol commands