diff options
Diffstat (limited to 'eclipse')
12 files changed, 732 insertions, 337 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/META-INF/MANIFEST.MF index e2effdc..56fe874 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/META-INF/MANIFEST.MF @@ -5,4 +5,5 @@ Bundle-SymbolicName: com.android.ide.eclipse.gldebugger.tests Bundle-Version: 16.0.0.qualifier Bundle-RequiredExecutionEnvironment: J2SE-1.5 Require-Bundle: org.junit4;bundle-version="4.5.0", - com.android.ide.eclipse.gldebugger + com.android.ide.eclipse.gldebugger, + org.eclipse.swt diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/src/com/android/ide/eclipse/gltrace/format/GLAPISpecTest.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/src/com/android/ide/eclipse/gltrace/format/GLAPISpecTest.java new file mode 100644 index 0000000..4a4d070 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/src/com/android/ide/eclipse/gltrace/format/GLAPISpecTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011 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. + */ + +package com.android.ide.eclipse.gltrace.format; + +import static org.junit.Assert.*; + +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +public class GLAPISpecTest { + @Test + public void testParser() { + String returnType = "void"; + String funcName = "glDiscardFramebufferEXT"; + List<String> args = Arrays.asList( + "GLenum target", + "GLsizei numAttachments", + "const GLenum* attachments"); + + GLAPISpec spec = GLAPISpec.parseLine(createSpec(returnType, funcName, args)); + + assertEquals(Type.VOID, spec.getReturnValue().getDataType()); + assertEquals(returnType, spec.getReturnValue().getCType()); + assertEquals(funcName, spec.getFunction()); + + List<GLDataTypeSpec> argSpecs = spec.getArgs(); + assertEquals(argSpecs.size(), args.size()); + + GLDataTypeSpec argSpec = argSpecs.get(0); + assertEquals(argSpec.getArgName(), "target"); + assertEquals(argSpec.getDataType(), Type.ENUM); + assertEquals(argSpec.isPointer(), false); + + argSpec = argSpecs.get(2); + assertEquals(argSpec.getArgName(), "attachments"); + assertEquals(argSpec.getDataType(), Type.ENUM); + assertEquals(argSpec.isPointer(), true); + } + + private String createSpec(String returnType, String funcName, List<String> args) { + StringBuffer sb = new StringBuffer(); + sb.append(String.format("%s, %s", returnType, funcName)); + + if (args != null) { + sb.append(", "); + for (int i = 0; i < args.size(); i++) { + sb.append(args.get(i)); + if (i != args.size() - 1) { + sb.append(", "); + } + } + } + + return sb.toString(); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/src/com/android/ide/eclipse/gltrace/format/GLCallFormatterTest.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/src/com/android/ide/eclipse/gltrace/format/GLCallFormatterTest.java new file mode 100644 index 0000000..115ce32 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger.tests/src/com/android/ide/eclipse/gltrace/format/GLCallFormatterTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2011 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. + */ + +package com.android.ide.eclipse.gltrace.format; + +import static org.junit.Assert.*; + +import com.android.ide.eclipse.gldebugger.GLEnum; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Builder; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function; +import com.android.ide.eclipse.gltrace.model.GLCall; +import com.google.protobuf.ByteString; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GLCallFormatterTest { + private static final List<String> API_SPECS = Arrays.asList( + "void, glBindBuffer, GLenum target, GLuint buffer", + "const GLchar*, glGetString, GLenum name", + "void, glMultMatrixf, const GLfloat* m", + "GLenum, eglBindAPI, GLEnum arg", + "void, glTexImage2D, GLint level, GLsizei width, const GLvoid* pixels"); + private static GLCallFormatter sGLCallFormatter; + + static { + Map<String, GLAPISpec> specs = new HashMap<String, GLAPISpec>(API_SPECS.size()); + + for (String specString: API_SPECS) { + GLAPISpec spec = GLAPISpec.parseLine(specString); + specs.put(spec.getFunction(), spec); + } + + sGLCallFormatter = new GLCallFormatter(specs); + } + + @Test + public void testBindBuffer() { + GLEnum arg1 = GLEnum.GL_ELEMENT_ARRAY_BUFFER; + int arg2 = 10; + + GLCall call = constructGLCall(null, Function.glBindBuffer, + createEnumDataType(arg1.value), + createIntegerDataType(arg2)); + + String expected = String.format("glBindBuffer(target = %s, buffer = %s)", + arg1.toString(), + Integer.toString(arg2)); + String actual = sGLCallFormatter.formatGLCall(call); + + assertEquals(expected, actual); + } + + @Test + public void testGlGetString() { + String retValue = "testString"; + GLEnum arg1 = GLEnum.GL_RENDERER; + + GLCall call = constructGLCall( + createStringDataType(retValue), + Function.glGetString, + createEnumDataType(arg1.value)); + String expected = String.format("%s(name = %s) = (const GLchar*) %s", Function.glGetString, + arg1.toString(), retValue); + String actual = sGLCallFormatter.formatGLCall(call); + + assertEquals(expected, actual); + } + + @Test + public void testGLEnum0() { + // an enum of value 0 should equal GL_POINTS if it is an argument, + // and GL_NO_ERROR if it is a return value + GLCall call = constructGLCall( + createEnumDataType(0), + Function.eglBindAPI, + createEnumDataType(0)); + String expected = "eglBindAPI(arg = GL_POINTS) = (GLenum) GL_NO_ERROR"; + String actual = sGLCallFormatter.formatGLCall(call); + + assertEquals(expected, actual); + } + + @Test + public void testMessageWithPointer() { + GLCall call = constructGLCall(null, + Function.glTexImage2D, + createIntegerDataType(1), + createIntegerDataType(2), + createIntegerPointerDataType(0xbadc0ffe)); + String expected = "glTexImage2D(level = 1, width = 2, pixels = 0xbadc0ffe)"; + String actual = sGLCallFormatter.formatGLCall(call); + + assertEquals(expected, actual); + } + + @Test + public void testMessageWithMismatchedPointer() { + // "void, glMultMatrixf, const GLfloat* m", + GLCall call = constructGLCall(null, + Function.glMultMatrixf, + createIntegerDataType(0xbadc0ffe)); + + String expected = "glMultMatrixf(m = 0xbadc0ffe)"; + String actual = sGLCallFormatter.formatGLCall(call); + + assertEquals(expected, actual); + } + + private DataType createStringDataType(String retValue) { + return DataType.newBuilder() + .addCharValue(ByteString.copyFromUtf8(retValue)) + .setIsArray(true) + .setType(Type.CHAR) + .build(); + } + + private DataType createIntegerDataType(int val) { + return DataType.newBuilder() + .addIntValue(val) + .setIsArray(false) + .setType(Type.INT) + .build(); + } + + private DataType createIntegerPointerDataType(int val) { + return DataType.newBuilder() + .addIntValue(val) + .setIsArray(true) + .setType(Type.INT) + .build(); + } + + private DataType createEnumDataType(int val) { + return DataType.newBuilder() + .addIntValue(val) + .setIsArray(false) + .setType(Type.ENUM) + .build(); + } + + private GLCall constructGLCall(DataType retValue, Function func, DataType...args) { + Builder builder = GLMessage.newBuilder(); + builder.setFunction(func); + + // set required fields we don't care about in these tests + builder.setContextId(0); + builder.setStartTime(0); + builder.setDuration(0); + + // set return value if any + if (retValue != null) { + builder.setReturnValue(retValue); + } + + for (DataType arg: args) { + builder.addArgs(arg); + } + + return new GLCall(0, 0, builder.build(), null); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.gldebugger/META-INF/MANIFEST.MF index 138e20d..feb16bb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/META-INF/MANIFEST.MF @@ -17,4 +17,7 @@ Bundle-ClassPath: libs/host-libprotobuf-java-2.3.0-lite.jar, libs/ddmlib.jar, . Bundle-Vendor: The Android Open Source Project -Export-Package: com.android.ide.eclipse.gldebugger;x-friends:="com.android.ide.eclipse.gldebugger.tests" +Export-Package: com.android.ide.eclipse.gldebugger;x-friends:="com.android.ide.eclipse.gldebugger.tests", + com.android.ide.eclipse.gltrace;x-friends:="com.android.ide.eclipse.gldebugger.tests", + com.android.ide.eclipse.gltrace.format;x-friends:="com.android.ide.eclipse.gldebugger.tests", + com.android.ide.eclipse.gltrace.model;x-friends:="com.android.ide.eclipse.gldebugger.tests" diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/entries.in b/eclipse/plugins/com.android.ide.eclipse.gldebugger/entries.in index e2c718c..eb71ad2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/entries.in +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/entries.in @@ -190,7 +190,7 @@ void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, GLcha void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params -const GLubyte* , glGetString, GLenum name +const GLchar* , glGetString, GLenum name void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat* params void, glGetTexEnviv, GLenum env, GLenum pname, GLint* params void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed* params diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLCallFormatter.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLCallFormatter.java deleted file mode 100644 index 4e67eaa..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLCallFormatter.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -package com.android.ide.eclipse.gltrace; - -import com.android.ide.eclipse.gldebugger.GLEnum; -import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType; -import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type; -import com.android.ide.eclipse.gltrace.model.GLCall; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * GLCallFormatter is used to format and create a string representation for a {@link GLCall}. - * It reads in the GL API definitions from a file to know about all the GL calls, - * their return types and their arguments. Using this information, each GLCall is - * parsed and formatted appropriately for display. - */ -public class GLCallFormatter { - private static final String GLES2_ENTRIES_HEADER_V1 = - "# com.android.ide.eclipse.gltrace.glentries, v1"; - - private Map<String, GLAPISpec> mAPISpecs = new HashMap<String, GLCallFormatter.GLAPISpec>(400); - - /** - * Initialize the GL Function Call formatter - * @param specs OpenGL API specs - */ - public GLCallFormatter(InputStream specs) { - BufferedReader reader = new BufferedReader(new InputStreamReader(specs)); - - try{ - String header = reader.readLine().trim(); - assert header.equals(GLES2_ENTRIES_HEADER_V1); - - while (true) { - String line = reader.readLine(); - if (line == null) { - break; - } - - // strip away the comments - int commentPos = line.indexOf('#'); - if (commentPos > 0) { - line = line.substring(0, commentPos); - } - line = line.trim(); - - // parse non empty lines - if (line.length() > 0) { - parseLine(line); - } - } - } catch (IOException e) { - throw new IllegalArgumentException("Unexpected IO Exception while parsing GL specs", e); - } - - try { - specs.close(); - } catch (IOException e) { - // ignore exception while closing stream - } - } - - private void parseLine(String line) { - // Every line is of the following format: - // <ret_type> <func_name> <args> - // where <args> = void | [const] <arg_type> <arg_name> - List<String> words = Arrays.asList(line.split(",")); - - String retType = words.get(0).trim(); - String func = words.get(1).trim(); - List<String> argDefinitions = words.subList(2, words.size()); - - List<GLArgumentSpec> glArgs = new ArrayList<GLArgumentSpec>(argDefinitions.size()/2); - for (String argDefn: argDefinitions) { - // an argDefn is something like: "const GLvoid* data" - argDefn = argDefn.trim(); - int lastSeparator = argDefn.lastIndexOf(' '); - if (lastSeparator == -1) { - // no space => a void type with no argument name - glArgs.add(new GLArgumentSpec(argDefn, null)); - } else { - // everything upto the last space is the type, and the last word is the variable - // name - glArgs.add(new GLArgumentSpec(argDefn.substring(0, lastSeparator), - argDefn.substring(lastSeparator + 1))); - } - } - - mAPISpecs.put(func, new GLAPISpec(func, retType, glArgs)); - } - - public String formatGLCall(GLCall glCall) { - GLAPISpec apiSpec = mAPISpecs.get(glCall.getFunction().toString()); - if (apiSpec == null) { - return null; - } - - return String.format("%s %s(%s)", apiSpec.getReturnType(), - apiSpec.getFunction(), - formatArgs(glCall, apiSpec.getArgs())); - } - - private String formatArgs(GLCall glCall, List<GLArgumentSpec> argSpecs) { - StringBuffer sb = new StringBuffer(); - - for (int i = 0; i < argSpecs.size(); i++) { - GLArgumentSpec argSpec = argSpecs.get(i); - - Type typeSpec = argSpec.getArgType(); - if (typeSpec == Type.VOID) { - sb.append("void"); - } else { - sb.append(argSpec.getArgName()); - sb.append(" = "); - sb.append(formatArgValue(glCall.getArg(i), typeSpec)); - } - - if (i < argSpecs.size() - 1) { - sb.append(", "); - } - } - - return sb.toString(); - } - - private String formatArgValue(DataType arg, Type typeSpec) { - if (arg.getIsArray()) { - return formatPointer(arg); - } - - switch (typeSpec) { - case VOID: - return ""; - case BOOL: - return Boolean.toString(arg.getBoolValue(0)); - case FLOAT: - return String.format("%f", arg.getFloatValue(0)); - case INT: - return Integer.toString(arg.getIntValue(0)); - case ENUM: - return GLEnum.valueOf(arg.getIntValue(0)).toString(); - default: - return "(unknown type)"; - } - } - - private String formatPointer(DataType args) { - // Display as array if possible - switch (args.getType()) { - case BOOL: - return args.getBoolValueList().toString(); - case FLOAT: - return args.getFloatValueList().toString(); - case INT: - return args.getIntValueList().toString(); - case CHAR: - return args.getCharValueList().get(0).toStringUtf8(); - } - - // We have a pointer, but we don't have the data pointed to. - // Just format and return the pointer (points to device memory) - if (args.getIntValue(0) == 0) { - return "NULL"; - } else { - return String.format("0x%x", args.getIntValue(0)); - } - } - - private static class GLAPISpec { - private final String mGLFunction; - private final String mReturnType; - private final List<GLArgumentSpec> mArgs; - - public GLAPISpec(String glFunction, String returnType, List<GLArgumentSpec> args) { - mGLFunction = glFunction; - mReturnType = returnType; - mArgs = args; - } - - public String getFunction() { - return mGLFunction; - } - - public String getReturnType() { - return mReturnType; - } - - public List<GLArgumentSpec> getArgs() { - return mArgs; - } - } - - private static class GLArgumentSpec { - private final Type mType; - private final String mName; - - public GLArgumentSpec(String type, String name) { - mType = getType(type); - mName = name; - } - - private Type getType(String type) { - type = type.toLowerCase(); - - // We use type.contains() rather than type.equals since we are matching against - // the type name along with qualifiers. e.g. "void", "GLvoid" and "void*" should - // all be assigned the same type. - if (type.contains("boolean")) { - return Type.BOOL; - } else if (type.contains("enum")) { - return Type.ENUM; - } else if (type.contains("float") || type.contains("clampf")) { - return Type.FLOAT; - } else if (type.contains("void")) { - return Type.VOID; - } else if (type.contains("char")) { - return Type.CHAR; - } else { - // Matches all of the following types: - // glclampx, gluint, glint, glshort, glsizei, glfixed, - // glsizeiptr, glintptr, glbitfield, glfixed, glubyte. - // We might do custom formatting for these types in the future. - return Type.INT; - } - } - - public Type getArgType() { - return mType; - } - - public String getArgName() { - return mName; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLProtoBuf.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLProtoBuf.java index ceb32fc..247dba4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLProtoBuf.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLProtoBuf.java @@ -2055,15 +2055,29 @@ public final class GLProtoBuf { public boolean hasContextId() { return hasContextId; } public int getContextId() { return contextId_; } - // required .android.gltrace.GLMessage.Function function = 2 [default = invalid]; - public static final int FUNCTION_FIELD_NUMBER = 2; + // required int64 start_time = 2; + public static final int START_TIME_FIELD_NUMBER = 2; + private boolean hasStartTime; + private long startTime_ = 0L; + public boolean hasStartTime() { return hasStartTime; } + public long getStartTime() { return startTime_; } + + // required int32 duration = 3; + public static final int DURATION_FIELD_NUMBER = 3; + private boolean hasDuration; + private int duration_ = 0; + public boolean hasDuration() { return hasDuration; } + public int getDuration() { return duration_; } + + // required .android.gltrace.GLMessage.Function function = 4 [default = invalid]; + public static final int FUNCTION_FIELD_NUMBER = 4; private boolean hasFunction; private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function function_; public boolean hasFunction() { return hasFunction; } public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function getFunction() { return function_; } - // repeated .android.gltrace.GLMessage.DataType args = 3; - public static final int ARGS_FIELD_NUMBER = 3; + // repeated .android.gltrace.GLMessage.DataType args = 5; + public static final int ARGS_FIELD_NUMBER = 5; private java.util.List<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType> args_ = java.util.Collections.emptyList(); public java.util.List<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType> getArgsList() { @@ -2074,22 +2088,15 @@ public final class GLProtoBuf { return args_.get(index); } - // optional .android.gltrace.GLMessage.DataType returnValue = 4; - public static final int RETURNVALUE_FIELD_NUMBER = 4; + // optional .android.gltrace.GLMessage.DataType returnValue = 6; + public static final int RETURNVALUE_FIELD_NUMBER = 6; private boolean hasReturnValue; private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType returnValue_; public boolean hasReturnValue() { return hasReturnValue; } public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType getReturnValue() { return returnValue_; } - // optional float duration = 5; - public static final int DURATION_FIELD_NUMBER = 5; - private boolean hasDuration; - private float duration_ = 0F; - public boolean hasDuration() { return hasDuration; } - public float getDuration() { return duration_; } - - // optional .android.gltrace.GLMessage.FrameBuffer fb = 6; - public static final int FB_FIELD_NUMBER = 6; + // optional .android.gltrace.GLMessage.FrameBuffer fb = 7; + public static final int FB_FIELD_NUMBER = 7; private boolean hasFb; private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer fb_; public boolean hasFb() { return hasFb; } @@ -2102,6 +2109,8 @@ public final class GLProtoBuf { } public final boolean isInitialized() { if (!hasContextId) return false; + if (!hasStartTime) return false; + if (!hasDuration) return false; if (!hasFunction) return false; for (com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType element : getArgsList()) { if (!element.isInitialized()) return false; @@ -2121,20 +2130,23 @@ public final class GLProtoBuf { if (hasContextId()) { output.writeInt32(1, getContextId()); } + if (hasStartTime()) { + output.writeInt64(2, getStartTime()); + } + if (hasDuration()) { + output.writeInt32(3, getDuration()); + } if (hasFunction()) { - output.writeEnum(2, getFunction().getNumber()); + output.writeEnum(4, getFunction().getNumber()); } for (com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType element : getArgsList()) { - output.writeMessage(3, element); + output.writeMessage(5, element); } if (hasReturnValue()) { - output.writeMessage(4, getReturnValue()); - } - if (hasDuration()) { - output.writeFloat(5, getDuration()); + output.writeMessage(6, getReturnValue()); } if (hasFb()) { - output.writeMessage(6, getFb()); + output.writeMessage(7, getFb()); } } @@ -2148,25 +2160,29 @@ public final class GLProtoBuf { size += com.google.protobuf.CodedOutputStream .computeInt32Size(1, getContextId()); } + if (hasStartTime()) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(2, getStartTime()); + } + if (hasDuration()) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(3, getDuration()); + } if (hasFunction()) { size += com.google.protobuf.CodedOutputStream - .computeEnumSize(2, getFunction().getNumber()); + .computeEnumSize(4, getFunction().getNumber()); } for (com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType element : getArgsList()) { size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, element); + .computeMessageSize(5, element); } if (hasReturnValue()) { size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, getReturnValue()); - } - if (hasDuration()) { - size += com.google.protobuf.CodedOutputStream - .computeFloatSize(5, getDuration()); + .computeMessageSize(6, getReturnValue()); } if (hasFb()) { size += com.google.protobuf.CodedOutputStream - .computeMessageSize(6, getFb()); + .computeMessageSize(7, getFb()); } memoizedSerializedSize = size; return size; @@ -2323,6 +2339,12 @@ public final class GLProtoBuf { if (other.hasContextId()) { setContextId(other.getContextId()); } + if (other.hasStartTime()) { + setStartTime(other.getStartTime()); + } + if (other.hasDuration()) { + setDuration(other.getDuration()); + } if (other.hasFunction()) { setFunction(other.getFunction()); } @@ -2335,9 +2357,6 @@ public final class GLProtoBuf { if (other.hasReturnValue()) { mergeReturnValue(other.getReturnValue()); } - if (other.hasDuration()) { - setDuration(other.getDuration()); - } if (other.hasFb()) { mergeFb(other.getFb()); } @@ -2365,6 +2384,14 @@ public final class GLProtoBuf { break; } case 16: { + setStartTime(input.readInt64()); + break; + } + case 24: { + setDuration(input.readInt32()); + break; + } + case 32: { int rawValue = input.readEnum(); com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function value = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function.valueOf(rawValue); if (value != null) { @@ -2372,13 +2399,13 @@ public final class GLProtoBuf { } break; } - case 26: { + case 42: { com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Builder subBuilder = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.newBuilder(); input.readMessage(subBuilder, extensionRegistry); addArgs(subBuilder.buildPartial()); break; } - case 34: { + case 50: { com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Builder subBuilder = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.newBuilder(); if (hasReturnValue()) { subBuilder.mergeFrom(getReturnValue()); @@ -2387,11 +2414,7 @@ public final class GLProtoBuf { setReturnValue(subBuilder.buildPartial()); break; } - case 45: { - setDuration(input.readFloat()); - break; - } - case 50: { + case 58: { com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.Builder subBuilder = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.newBuilder(); if (hasFb()) { subBuilder.mergeFrom(getFb()); @@ -2423,7 +2446,43 @@ public final class GLProtoBuf { return this; } - // required .android.gltrace.GLMessage.Function function = 2 [default = invalid]; + // required int64 start_time = 2; + public boolean hasStartTime() { + return result.hasStartTime(); + } + public long getStartTime() { + return result.getStartTime(); + } + public Builder setStartTime(long value) { + result.hasStartTime = true; + result.startTime_ = value; + return this; + } + public Builder clearStartTime() { + result.hasStartTime = false; + result.startTime_ = 0L; + return this; + } + + // required int32 duration = 3; + public boolean hasDuration() { + return result.hasDuration(); + } + public int getDuration() { + return result.getDuration(); + } + public Builder setDuration(int value) { + result.hasDuration = true; + result.duration_ = value; + return this; + } + public Builder clearDuration() { + result.hasDuration = false; + result.duration_ = 0; + return this; + } + + // required .android.gltrace.GLMessage.Function function = 4 [default = invalid]; public boolean hasFunction() { return result.hasFunction(); } @@ -2444,7 +2503,7 @@ public final class GLProtoBuf { return this; } - // repeated .android.gltrace.GLMessage.DataType args = 3; + // repeated .android.gltrace.GLMessage.DataType args = 5; public java.util.List<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType> getArgsList() { return java.util.Collections.unmodifiableList(result.args_); } @@ -2495,7 +2554,7 @@ public final class GLProtoBuf { return this; } - // optional .android.gltrace.GLMessage.DataType returnValue = 4; + // optional .android.gltrace.GLMessage.DataType returnValue = 6; public boolean hasReturnValue() { return result.hasReturnValue(); } @@ -2532,25 +2591,7 @@ public final class GLProtoBuf { return this; } - // optional float duration = 5; - public boolean hasDuration() { - return result.hasDuration(); - } - public float getDuration() { - return result.getDuration(); - } - public Builder setDuration(float value) { - result.hasDuration = true; - result.duration_ = value; - return this; - } - public Builder clearDuration() { - result.hasDuration = false; - result.duration_ = 0F; - return this; - } - - // optional .android.gltrace.GLMessage.FrameBuffer fb = 6; + // optional .android.gltrace.GLMessage.FrameBuffer fb = 7; public boolean hasFb() { return result.hasFb(); } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java index acfd576..fc6ce18 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java @@ -16,8 +16,9 @@ package com.android.ide.eclipse.gltrace.editors; -import com.android.ide.eclipse.gltrace.GLCallFormatter; import com.android.ide.eclipse.gltrace.TraceFileParserTask; +import com.android.ide.eclipse.gltrace.format.GLAPISpec; +import com.android.ide.eclipse.gltrace.format.GLCallFormatter; import com.android.ide.eclipse.gltrace.model.GLCall; import com.android.ide.eclipse.gltrace.model.GLTrace; import com.android.ide.eclipse.gltrace.views.GLFramebufferView; @@ -70,7 +71,6 @@ import java.util.regex.Pattern; public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvider { public static final String ID = "com.android.ide.eclipse.gltrace.GLFunctionTrace"; //$NON-NLS-1$ - private static final String GL_SPECS_FILE = "/entries.in"; //$NON-NLS-1$ private static final String DEFAULT_FILTER_MESSAGE = "Filter list of OpenGL calls. Accepts Java regexes."; // TODO: The thumbnail width & height are constant right now, but should be scaled @@ -81,8 +81,8 @@ public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvi /** Height of thumbnail images of the framebuffer. */ private static final int THUMBNAIL_HEIGHT = 50; - private final GLCallFormatter mGLCallFormatter = - new GLCallFormatter(getClass().getResourceAsStream(GL_SPECS_FILE)); + private static final GLCallFormatter sGLCallFormatter = + new GLCallFormatter(GLAPISpec.getSpecs()); private String mFilePath; private Scale mFrameSelectionScale; @@ -361,7 +361,7 @@ public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvi return Integer.toString(c.getContextId()); default: try { - return formatGLCall(c); + return sGLCallFormatter.formatGLCall(c); } catch (Exception e) { // in case of any formatting errors, just return the function name. return c.getFunction().toString(); @@ -370,15 +370,6 @@ public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvi } } - private String formatGLCall(GLCall c) { - String result = mGLCallFormatter.formatGLCall(c); - if (result == null) { - result = c.getFunction().toString(); - } - - return result; - } - private static class GLCallFilter extends ViewerFilter { private final List<Pattern> mPatterns = new ArrayList<Pattern>(); diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLAPISpec.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLAPISpec.java new file mode 100644 index 0000000..c15cc20 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLAPISpec.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2011 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. + */ + +package com.android.ide.eclipse.gltrace.format; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Model a single GL API function call's specification. + */ +public class GLAPISpec { + private static final String GL_SPECS_FILE = "/entries.in"; //$NON-NLS-1$ + private static final String GLES2_ENTRIES_HEADER_V1 = + "# com.android.ide.eclipse.gltrace.glentries, v1"; //$NON-NLS-1$ + private static Map<String, GLAPISpec> sApiSpecs; + + private final String mGLFunction; + private final GLDataTypeSpec mReturnType; + private final List<GLDataTypeSpec> mArgs; + + private GLAPISpec(String glFunction, GLDataTypeSpec returnType, List<GLDataTypeSpec> args) { + mGLFunction = glFunction; + mReturnType = returnType; + mArgs = args; + } + + public String getFunction() { + return mGLFunction; + } + + public GLDataTypeSpec getReturnValue() { + return mReturnType; + } + + public List<GLDataTypeSpec> getArgs() { + return mArgs; + } + + public static Map<String, GLAPISpec> getSpecs() { + if (sApiSpecs == null) { + sApiSpecs = parseApiSpecs(GLAPISpec.class.getResourceAsStream(GL_SPECS_FILE)); + } + + return sApiSpecs; + } + + private static Map<String, GLAPISpec> parseApiSpecs(InputStream specFile) { + BufferedReader reader = new BufferedReader(new InputStreamReader(specFile)); + Map<String, GLAPISpec> specs = new HashMap<String, GLAPISpec>(400); + + try{ + String header = reader.readLine().trim(); + assert header.equals(GLES2_ENTRIES_HEADER_V1); + + String line; + while ((line = reader.readLine()) != null) { + // strip away the comments + int commentPos = line.indexOf('#'); + if (commentPos > 0) { + line = line.substring(0, commentPos); + } + line = line.trim(); + + // parse non empty lines + if (line.length() > 0) { + GLAPISpec spec = parseLine(line); + specs.put(spec.getFunction(), spec); + } + } + + specFile.close(); + } catch (IOException e) { + // this is unlikely to happen as the file is present within this .jar file. + // Even if it does happen, we just return whatever we've read till now. The net + // impact will be that the function calls will not be parsed fully and will just + // display the function name. + } + + return specs; + } + + /** + * Parse a GL API Specification entry from "/entries.in". Each line is of the format: + * {@code returnType, funcName, arg*}. This method is package private for testing. + */ + static GLAPISpec parseLine(String line) { + List<String> words = Arrays.asList(line.split(",")); + + String retType = words.get(0).trim(); + String func = words.get(1).trim(); + List<String> argDefinitions = words.subList(2, words.size()); + + List<GLDataTypeSpec> glArgs = new ArrayList<GLDataTypeSpec>(argDefinitions.size()/2); + for (String argDefn: argDefinitions) { + // an argDefn is something like: "const GLvoid* data" + argDefn = argDefn.trim(); + int lastSeparator = argDefn.lastIndexOf(' '); + if (lastSeparator == -1) { + // no space => a void type with no argument name + glArgs.add(new GLDataTypeSpec(argDefn, null)); + } else { + // everything upto the last space is the type + String type = argDefn.substring(0, lastSeparator); + + // and the last word is the variable name + String name = argDefn.substring(lastSeparator + 1); + glArgs.add(new GLDataTypeSpec(type, name)); + } + } + + return new GLAPISpec(func, new GLDataTypeSpec(retType, null), glArgs); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLCallFormatter.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLCallFormatter.java new file mode 100644 index 0000000..7da9831 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLCallFormatter.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2011 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. + */ + +package com.android.ide.eclipse.gltrace.format; + +import com.android.ide.eclipse.gldebugger.GLEnum; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type; +import com.android.ide.eclipse.gltrace.model.GLCall; + +import java.util.List; +import java.util.Map; + +/** + * GLCallFormatter is used to format and create a string representation for a {@link GLCall}. + * It is provided with a specification for all GL Functions. Using this information, each GLCall is + * parsed and formatted appropriately for display. + */ +public class GLCallFormatter { + private static final String GL_NO_ERROR = "GL_NO_ERROR"; + private Map<String, GLAPISpec> mAPISpecs; + private enum DataTypeContext { CONTEXT_ARGUMENT, CONTEXT_RETURNVALUE }; + + public GLCallFormatter(Map<String, GLAPISpec> specs) { + mAPISpecs = specs; + } + + public String formatGLCall(GLCall glCall) { + GLAPISpec apiSpec = mAPISpecs.get(glCall.getFunction().toString()); + if (apiSpec == null) { + return glCall.getFunction().toString(); + } + + return formatCall(apiSpec, glCall) + formatReturnValue(apiSpec, glCall); + } + + private String formatReturnValue(GLAPISpec apiSpec, GLCall glCall) { + if (apiSpec.getReturnValue().getDataType() == Type.VOID) { + return ""; + } + + GLDataTypeSpec returnSpec = apiSpec.getReturnValue(); + return String.format(" = (%s) %s", returnSpec.getCType(), //$NON-NLS-1$ + formatDataValue(glCall.getReturnValue(), + returnSpec, + DataTypeContext.CONTEXT_RETURNVALUE)); + } + + private String formatCall(GLAPISpec apiSpec, GLCall glCall) { + return String.format("%s(%s)", apiSpec.getFunction(), //$NON-NLS-1$ + formatArgs(glCall, apiSpec.getArgs())); + } + + private String formatArgs(GLCall glCall, List<GLDataTypeSpec> argSpecs) { + int sizeEstimate = 10 + argSpecs.size() * 5; + StringBuilder sb = new StringBuilder(sizeEstimate); + + for (int i = 0; i < argSpecs.size(); i++) { + GLDataTypeSpec argSpec = argSpecs.get(i); + + if (argSpec.getDataType() == Type.VOID && !argSpec.isPointer()) { + sb.append("void"); //$NON-NLS-1$ + } else { + sb.append(argSpec.getArgName()); + sb.append(" = "); //$NON-NLS-1$ + sb.append(formatDataValue(glCall.getArg(i), + argSpec, + DataTypeContext.CONTEXT_ARGUMENT)); + } + + if (i < argSpecs.size() - 1) { + sb.append(", "); //$NON-NLS-1$ + } + } + + return sb.toString(); + } + + private String formatDataValue(DataType var, GLDataTypeSpec typeSpec, DataTypeContext context) { + if (typeSpec.isPointer()) { + return formatPointer(var, typeSpec.getDataType()); + } + + switch (typeSpec.getDataType()) { + case VOID: + return ""; + case BOOL: + return Boolean.toString(var.getBoolValue(0)); + case FLOAT: + return String.format("%f", var.getFloatValue(0)); //$NON-NLS-1$ + case INT: + return Integer.toString(var.getIntValue(0)); + case ENUM: + if (var.getIntValue(0) == 0 && context == DataTypeContext.CONTEXT_RETURNVALUE) { + return GL_NO_ERROR; + } else { + return GLEnum.valueOf(var.getIntValue(0)).toString(); + } + default: + return "(unknown type)"; //$NON-NLS-1$ + } + } + + private String formatPointer(DataType var, Type typeSpec) { + if (var.getType() != typeSpec) { + // the type of the data in the message does not match expected specification. + // in such a case, just print the data as a pointer and don't try to interpret it. + if (var.getIntValueCount() > 0) { + return String.format("0x%x", var.getIntValue(0)); //$NON-NLS-1$ + } else { + return "0x??"; //$NON-NLS-1$ + } + } + + // Display as array if possible + switch (var.getType()) { + case BOOL: + return var.getBoolValueList().toString(); + case FLOAT: + return var.getFloatValueList().toString(); + case INT: + return var.getIntValueList().toString(); + case CHAR: + return var.getCharValueList().get(0).toStringUtf8(); + } + + // We have a pointer, but we don't have the data pointed to. + // Just format and return the pointer (points to device memory) + if (var.getIntValue(0) == 0) { + return "NULL"; //$NON-NLS-1$ + } else { + return String.format("0x%x", var.getIntValue(0)); //$NON-NLS-1$ + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLDataTypeSpec.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLDataTypeSpec.java new file mode 100644 index 0000000..de9c9b6 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLDataTypeSpec.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 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. + */ + +package com.android.ide.eclipse.gltrace.format; + +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type; + +public class GLDataTypeSpec { + private final String mCType; + private final Type mType; + private final String mName; + private final boolean mIsPointer; + + public GLDataTypeSpec(String type, String name) { + mCType = type; + mName = name; + + mType = getDataType(type); + mIsPointer = type.contains("*"); //$NON-NLS-1$ + } + + private Type getDataType(String type) { + type = type.toLowerCase(); + + // We use type.contains() rather than type.equals since we are matching against + // the type name along with qualifiers. e.g. "void", "GLvoid" and "void*" should + // all be assigned the same type. + if (type.contains("boolean")) { //$NON-NLS-1$ + return Type.BOOL; + } else if (type.contains("enum")) { //$NON-NLS-1$ + return Type.ENUM; + } else if (type.contains("float") || type.contains("clampf")) { //$NON-NLS-1$ //$NON-NLS-2$ + return Type.FLOAT; + } else if (type.contains("void")) { //$NON-NLS-1$ + return Type.VOID; + } else if (type.contains("char")) { //$NON-NLS-1$ + return Type.CHAR; + } else { + // Matches all of the following types: + // glclampx, gluint, glint, glshort, glsizei, glfixed, + // glsizeiptr, glintptr, glbitfield, glfixed, glubyte. + // We might do custom formatting for these types in the future. + return Type.INT; + } + } + + public Type getDataType() { + return mType; + } + + public String getCType() { + return mCType; + } + + public String getArgName() { + return mName; + } + + public boolean isPointer() { + return mIsPointer; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java index 79a74e3..c868bde 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java @@ -78,6 +78,10 @@ public class GLCall { return mMessage.getFunction(); } + public DataType getReturnValue() { + return mMessage.getReturnValue(); + } + public int getContextId() { return mMessage.getContextId(); } |