@ -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 ( ) ;
// 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 ( "(" ) ;
int target = ( Integer ) args [ 0 ] ;
int param = ( Integer ) args [ 1 ] ;
int value = ( Integer ) args [ 2 ] ;
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 ] ;
System . out . print ( translateInteger ( methodName , val , i ) ) ;
printIntOrEnum ( methodName , val , i ) ;
} else if ( paramTypes [ i ] = = boolean . class ) {
printBoolean ( ( Boolean ) args [ i ] ) ;
} else if ( paramTypes [ i ] = = String . class ) {
System . out . print ( translateString ( ( String ) args [ i ] ) ) ;
printString ( ( 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 ) + "...\"" ) ;
printString ( arr [ 0 ] ) ;
} else {
System . out . print ( "\"" + arr [ 0 ] + "\"" ) ;
}
} else {
System . out . print ( "String[" + arr . length + "]" ) ;
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 ) ) ;
printOut ( ) ;
printIntOrEnum ( methodName , val , i ) ;
} else if ( buf . capacity ( ) = = 1 ) {
System . out . print ( "out=" + buf . get ( 0 ) ) ;
printOut ( ) ;
print ( Integer . toString ( buf . get ( 0 ) ) ) ;
} else {
System . out . print ( args [ i ] ) ;
printBuffer ( buf ) ;
}
} 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" ) ;
printOut ( ) ;
printBoolean ( bb . get ( 0 ) ! = 0 ) ;
} else {
System . out . print ( "out=GL_FALSE" ) ;
printBuffer ( bb ) ;
}
} else if ( args [ i ] instanceof Buffer ) {
printBuffer ( ( Buffer ) args [ i ] ) ;
} else if ( args [ i ] ! = null ) {
print ( args [ i ] . toString ( ) ) ;
} else {
System . out . print ( args [ i ] ) ;
}
} else {
System . out . print ( args [ i ] ) ;
printNull ( ) ;
}
if ( i ! = args . length - 1 ) {
System . out . print ( ", " ) ;
}
}
print ( ")" ) ;
}
System . out . print ( ")" ) ;
@Override
public Object invoke ( Object proxy , Method method , Object [ ] args ) throws Throwable {
String methodName = method . getName ( ) ;
printMethodName ( methodName ) ;
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" ) ;
} else {
System . out . println ( " = ???" ) ;
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 {
System . out . println ( ) ;
printNewLine ( ) ;
return method . invoke ( obj , args ) ;
}
}
return result ;
}
}