GLTracer: generate syntax highlighting and easier to read output

experimental
Kirill Vainer 9 years ago
parent 9da4b78830
commit e9245a753b
  1. 358
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java

@ -36,8 +36,14 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import java.util.HashMap;
/**
@ -51,6 +57,17 @@ public final class GLTracer implements InvocationHandler {
private final IntMap<String> constMap;
private static final HashMap<String, IntMap<Void>> nonEnumArgMap = new HashMap<String, IntMap<Void>>();
private static final String ANSI_RESET = "\u001B[0m";
private static final String ANSI_BRIGHT = "\u001B[1m";
private static final String ANSI_BLACK = "\u001B[30m";
private static final String ANSI_RED = "\u001B[31m";
private static final String ANSI_GREEN = "\u001B[32m";
private static final String ANSI_YELLOW = "\u001B[33m";
private static final String ANSI_BLUE = "\u001B[34m";
private static final String ANSI_MAGENTA = "\u001B[35m";
private static final String ANSI_CYAN = "\u001B[36m";
private static final String ANSI_WHITE = "\u001B[37m";
private static void noEnumArgs(String method, int... argSlots) {
IntMap<Void> argSlotsMap = new IntMap<Void>();
for (int argSlot : argSlots) {
@ -174,100 +191,287 @@ public final class GLTracer implements InvocationHandler {
new GLTracer(glInterface, constMap));
}
private String translateInteger(String method, int value, int argIndex) {
IntMap<Void> argSlotMap = nonEnumArgMap.get(method);
if (argSlotMap != null && argSlotMap.containsKey(argIndex)) {
return Integer.toString(value);
}
private void printStyle(String style, String string) {
System.out.print(style + string + ANSI_RESET);
}
private void print(String string) {
System.out.print(string);
}
private void printInt(int value) {
print(Integer.toString(value));
}
private void printEnum(int value) {
String enumName = constMap.get(value);
if (enumName != null) {
return enumName;
if (enumName.startsWith("GL_")) {
enumName = enumName.substring(3);
}
if (enumName.endsWith("_EXT") || enumName.endsWith("_ARB")) {
enumName = enumName.substring(0, enumName.length() - 4);
}
printStyle(ANSI_GREEN, enumName);
} else {
printStyle(ANSI_GREEN, "ENUM_" + Integer.toHexString(value));
}
}
private void printIntOrEnum(String method, int value, int argIndex) {
IntMap<Void> argSlotMap = nonEnumArgMap.get(method);
if (argSlotMap != null && argSlotMap.containsKey(argIndex)) {
printInt(value);
} else {
return "GL_ENUM_" + Integer.toHexString(value);
//throw new IllegalStateException("Untranslatable enum encountered on " + method +
// " at argument " + argIndex + " with value " + value);
printEnum(value);
}
}
private String translateString(String value) {
return "\"" + value.replaceAll("\0", "\\\\0") + "\"";
private void printNewLine() {
System.out.println();
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(obj, args);
String methodName = method.getName();
private void printString(String value) {
if (value.length() > 150) {
value = value.substring(0, 150) + "...";
}
StringBuilder sb = new StringBuilder();
sb.append(ANSI_YELLOW);
sb.append("\"");
sb.append(ANSI_RESET);
for (String line : value.split("\n")) {
sb.append(ANSI_YELLOW);
sb.append(line.replaceAll("\0", "\\\\0"));
sb.append(ANSI_RESET);
sb.append("\n");
}
if (sb.length() > 1 && sb.charAt(sb.length() - 1) == '\n') {
sb.setLength(sb.length() - 1);
}
sb.append(ANSI_YELLOW);
sb.append("\"");
sb.append(ANSI_RESET);
print(sb.toString());
}
private void printBoolean(boolean bool) {
printStyle(ANSI_BLUE, bool ? "true" : "false");
}
private void printBuffer(Buffer buffer) {
StringBuilder sb = new StringBuilder();
sb.append(ANSI_MAGENTA);
if (buffer instanceof ByteBuffer) {
sb.append("byte");
} else if (buffer instanceof ShortBuffer) {
sb.append("short");
} else if (buffer instanceof CharBuffer) {
sb.append("char");
} else if (buffer instanceof FloatBuffer) {
sb.append("float");
} else if (buffer instanceof IntBuffer) {
sb.append("int");
} else if (buffer instanceof LongBuffer) {
sb.append("long");
} else if (buffer instanceof DoubleBuffer) {
sb.append("double");
} else {
throw new UnsupportedOperationException();
}
sb.append(ANSI_RESET);
sb.append("[");
if (buffer.position() == 0
&& buffer.limit() == buffer.capacity()) {
// Common case. Just print buffer size.
sb.append(buffer.capacity());
} else {
sb.append("pos=").append(buffer.position());
sb.append(" lim=").append(buffer.limit());
sb.append(" cap=").append(buffer.capacity());
}
sb.append("]");
print(sb.toString());
}
private void printMethodName(String methodName) {
if (methodName.startsWith("gl")) {
System.out.print(methodName);
System.out.print("(");
if (args != null) {
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < args.length; i++) {
if (paramTypes[i] == int.class) {
int val = (Integer)args[i];
System.out.print(translateInteger(methodName, val, i));
} else if (paramTypes[i] == String.class) {
System.out.print(translateString((String)args[i]));
} else if (paramTypes[i] == String[].class) {
String[] arr = (String[]) args[i];
if (arr.length == 1) {
if (arr[0].length() > 150) {
System.out.print("\"" + arr[0].substring(0, 150) + "...\"");
} else {
System.out.print("\"" + arr[0] + "\"");
}
} else {
System.out.print("String[" + arr.length + "]");
}
} else if (args[i] instanceof IntBuffer) {
IntBuffer buf = (IntBuffer) args[i];
if (buf.capacity() == 16) {
int val = buf.get(0);
System.out.print("out=" + translateInteger(methodName, val, i));
} else if (buf.capacity() == 1) {
System.out.print("out=" + buf.get(0));
} else {
System.out.print(args[i]);
}
} else if (args[i] instanceof ByteBuffer) {
ByteBuffer bb = (ByteBuffer)args[i];
if (bb.capacity() == 250) {
if (bb.get(0) != 0) {
System.out.print("out=GL_TRUE");
} else {
System.out.print("out=GL_FALSE");
}
} else {
System.out.print(args[i]);
}
} else {
System.out.print(args[i]);
}
if (i != args.length - 1) {
System.out.print(", ");
}
// GL calls which actually draw (as opposed to change state)
// will be printed in darker color
methodName = methodName.substring(2);
if (methodName.equals("Clear")
|| methodName.equals("DrawRangeElements")) {
print(methodName);
} else {
if (methodName.endsWith("EXT")) {
methodName = methodName.substring(0, methodName.length() - 3);
}
printStyle(ANSI_BRIGHT, methodName);
}
} else if (methodName.equals("resetStats")) {
printStyle(ANSI_RED, "-- frame boundary --");
}
}
private void printArgsClear(int mask) {
boolean needAPipe = false;
print("(");
if ((mask & GL.GL_COLOR_BUFFER_BIT) != 0) {
printStyle(ANSI_GREEN, "COLOR_BUFFER_BIT");
needAPipe = true;
}
if ((mask & GL.GL_DEPTH_BUFFER_BIT) != 0) {
if (needAPipe) {
print(" | ");
}
printStyle(ANSI_GREEN, "DEPTH_BUFFER_BIT");
}
if ((mask & GL.GL_STENCIL_BUFFER_BIT) != 0) {
if (needAPipe) {
print(" | ");
}
printStyle(ANSI_GREEN, "STENCIL_BUFFER_BIT");
}
print(")");
}
private void printArgsTexParameter(Object[] args) {
print("(");
System.out.print(")");
int target = (Integer) args[0];
int param = (Integer) args[1];
int value = (Integer) args[2];
if (method.getReturnType() != void.class) {
if (result instanceof String) {
System.out.println(" = " + translateString((String)result));
} else if (method.getReturnType() == int.class) {
int val = (Integer)result;
System.out.println(" = " + translateInteger(methodName, val, -1));
} else if (method.getReturnType() == boolean.class) {
boolean val = (Boolean)result;
if (val) System.out.println(" = GL_TRUE");
else System.out.println(" = GL_FALSE");
printEnum(target);
print(", ");
printEnum(param);
print(", ");
if (param == GL.GL_TEXTURE_BASE_LEVEL
|| param == GL.GL_TEXTURE_MAX_LEVEL) {
printInt(value);
} else {
printEnum(value);
}
print(")");
}
private void printOut() {
printStyle(ANSI_CYAN, "out=");
}
private void printResult(String methodName, Object result, Class<?> returnType) {
if (returnType != void.class) {
print(" = ");
if (result instanceof String) {
printString((String) result);
} else if (returnType == int.class) {
int val = (Integer) result;
printIntOrEnum(methodName, val, -1);
} else if (returnType == boolean.class) {
printBoolean((Boolean)result);
} else {
print(" = ???");
}
}
}
private void printNull() {
printStyle(ANSI_BLUE, "null");
}
private void printArgs(String methodName, Object[] args, Class<?>[] paramTypes) {
if (methodName.equals("glClear")) {
printArgsClear((Integer)args[0]);
return;
} else if (methodName.equals("glTexParameteri")) {
printArgsTexParameter(args);
return;
}
if (args == null) {
print("()");
return;
}
print("(");
for (int i = 0; i < args.length; i++) {
if (paramTypes[i] == int.class) {
int val = (Integer)args[i];
printIntOrEnum(methodName, val, i);
} else if (paramTypes[i] == boolean.class) {
printBoolean((Boolean)args[i]);
} else if (paramTypes[i] == String.class) {
printString((String)args[i]);
} else if (paramTypes[i] == String[].class) {
String[] arr = (String[]) args[i];
if (arr.length == 1) {
printString(arr[0]);
} else {
System.out.println(" = ???");
print("string[" + arr.length + "]");
}
} else if (args[i] instanceof IntBuffer) {
IntBuffer buf = (IntBuffer) args[i];
if (buf.capacity() == 16) {
int val = buf.get(0);
printOut();
printIntOrEnum(methodName, val, i);
} else if (buf.capacity() == 1) {
printOut();
print(Integer.toString(buf.get(0)));
} else {
printBuffer(buf);
}
} else if (args[i] instanceof ByteBuffer) {
ByteBuffer bb = (ByteBuffer)args[i];
if (bb.capacity() == 250) {
printOut();
printBoolean(bb.get(0) != 0);
} else {
printBuffer(bb);
}
} else if (args[i] instanceof Buffer) {
printBuffer((Buffer)args[i]);
} else if (args[i] != null) {
print(args[i].toString());
} else {
System.out.println();
printNull();
}
if (i != args.length - 1) {
System.out.print(", ");
}
}
print(")");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
printMethodName(methodName);
if (methodName.startsWith("gl")) {
try {
// Try to evaluate result first, so we can see output values.
Object result = method.invoke(obj, args);
printArgs(methodName, args, method.getParameterTypes());
printResult(methodName, result, method.getReturnType());
printNewLine();
return result;
} catch (Throwable ex) {
// Execution failed, print args anyway
// but output values will be incorrect.
printArgs(methodName, args, method.getParameterTypes());
printNewLine();
System.out.println("\tException occurred!");
System.out.println(ex.toString());
throw ex;
}
} else {
printNewLine();
return method.invoke(obj, args);
}
return result;
}
}

Loading…
Cancel
Save