1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.gltrace.format; 18 19 import com.android.ide.eclipse.gltrace.GLEnum; 20 import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage; 21 import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType; 22 import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type; 23 24 import java.util.List; 25 import java.util.Map; 26 27 /** 28 * GLMessageFormatter is used to format and create a string representation for a {@link GLMessage}. 29 * It is provided with a specification for all GL Functions. Using this information, each 30 * GLMessage is parsed and formatted appropriately for display. 31 */ 32 public class GLMessageFormatter { 33 private static final String GL_NO_ERROR = "GL_NO_ERROR"; 34 private Map<String, GLAPISpec> mAPISpecs; 35 private enum DataTypeContext { CONTEXT_ARGUMENT, CONTEXT_RETURNVALUE }; 36 GLMessageFormatter(Map<String, GLAPISpec> specs)37 public GLMessageFormatter(Map<String, GLAPISpec> specs) { 38 mAPISpecs = specs; 39 } 40 formatGLMessage(GLMessage glMessage)41 public String formatGLMessage(GLMessage glMessage) { 42 GLAPISpec apiSpec = mAPISpecs.get(glMessage.getFunction().toString()); 43 if (apiSpec == null) { 44 return glMessage.getFunction().toString(); 45 } 46 47 return formatCall(apiSpec, glMessage) + formatReturnValue(apiSpec, glMessage); 48 } 49 formatReturnValue(GLAPISpec apiSpec, GLMessage glMessage)50 private String formatReturnValue(GLAPISpec apiSpec, GLMessage glMessage) { 51 if (apiSpec.getReturnValue().getDataType() == Type.VOID) { 52 return ""; 53 } 54 55 GLDataTypeSpec returnSpec = apiSpec.getReturnValue(); 56 return String.format(" = (%s) %s", returnSpec.getCType(), //$NON-NLS-1$ 57 formatDataValue(glMessage.getReturnValue(), 58 returnSpec, 59 DataTypeContext.CONTEXT_RETURNVALUE)); 60 } 61 formatCall(GLAPISpec apiSpec, GLMessage glMessage)62 private String formatCall(GLAPISpec apiSpec, GLMessage glMessage) { 63 return String.format("%s(%s)", apiSpec.getFunction(), //$NON-NLS-1$ 64 formatArgs(glMessage, apiSpec.getArgs())); 65 } 66 formatArgs(GLMessage glMessage, List<GLDataTypeSpec> argSpecs)67 private String formatArgs(GLMessage glMessage, List<GLDataTypeSpec> argSpecs) { 68 int sizeEstimate = 10 + argSpecs.size() * 5; 69 StringBuilder sb = new StringBuilder(sizeEstimate); 70 71 for (int i = 0; i < argSpecs.size(); i++) { 72 GLDataTypeSpec argSpec = argSpecs.get(i); 73 74 if (argSpec.getDataType() == Type.VOID && !argSpec.isPointer()) { 75 sb.append("void"); //$NON-NLS-1$ 76 } else { 77 sb.append(argSpec.getArgName()); 78 sb.append(" = "); //$NON-NLS-1$ 79 sb.append(formatDataValue(glMessage.getArgs(i), 80 argSpec, 81 DataTypeContext.CONTEXT_ARGUMENT)); 82 } 83 84 if (i < argSpecs.size() - 1) { 85 sb.append(", "); //$NON-NLS-1$ 86 } 87 } 88 89 return sb.toString(); 90 } 91 formatDataValue(DataType var, GLDataTypeSpec typeSpec, DataTypeContext context)92 private String formatDataValue(DataType var, GLDataTypeSpec typeSpec, DataTypeContext context) { 93 if (typeSpec.isPointer()) { 94 return formatPointer(var, typeSpec.getDataType()); 95 } 96 97 switch (typeSpec.getDataType()) { 98 case VOID: 99 return ""; 100 case BOOL: 101 return Boolean.toString(var.getBoolValue(0)); 102 case FLOAT: 103 return String.format("%f", var.getFloatValue(0)); //$NON-NLS-1$ 104 case INT: 105 return Integer.toString(var.getIntValue(0)); 106 case ENUM: 107 if (var.getIntValue(0) == 0 && context == DataTypeContext.CONTEXT_RETURNVALUE) { 108 return GL_NO_ERROR; 109 } else { 110 return GLEnum.valueOf(var.getIntValue(0)).toString(); 111 } 112 default: 113 return "(unknown type)"; //$NON-NLS-1$ 114 } 115 } 116 formatPointer(DataType var, Type typeSpec)117 private String formatPointer(DataType var, Type typeSpec) { 118 if (var.getType() != typeSpec && !isEnumTypeWithIntData(var, typeSpec)) { 119 // the type of the data in the message does not match expected specification. 120 // in such a case, just print the data as a pointer and don't try to interpret it. 121 if (var.getIntValueCount() > 0) { 122 return String.format("0x%x", var.getIntValue(0)); //$NON-NLS-1$ 123 } else { 124 return "0x??"; //$NON-NLS-1$ 125 } 126 } 127 128 // Display as array if possible 129 switch (typeSpec) { 130 case BOOL: 131 return var.getBoolValueList().toString(); 132 case FLOAT: 133 return var.getFloatValueList().toString(); 134 case INT: 135 return var.getIntValueList().toString(); 136 case CHAR: 137 return var.getCharValueList().get(0).toStringUtf8(); 138 case ENUM: 139 List<Integer> vals = var.getIntValueList(); 140 StringBuilder sb = new StringBuilder(vals.size() * 5); 141 sb.append('['); 142 for (Integer v: vals) { 143 sb.append(GLEnum.valueOf(v.intValue())); 144 } 145 sb.append(']'); 146 return sb.toString(); 147 case VOID: 148 if (var.getRawBytesList().size() > 0) { 149 return String.format("[ %d bytes ]", var.getRawBytesList().get(0).size()); //$NON-NLS-1$ 150 } 151 return "[]"; //$NON-NLS-1$ 152 } 153 154 // We have a pointer, but we don't have the data pointed to. 155 // Just format and return the pointer (points to device memory) 156 if (var.getIntValue(0) == 0) { 157 return "NULL"; //$NON-NLS-1$ 158 } else { 159 return String.format("0x%x", var.getIntValue(0)); //$NON-NLS-1$ 160 } 161 } 162 isEnumTypeWithIntData(DataType var, Type typeSpec)163 private boolean isEnumTypeWithIntData(DataType var, Type typeSpec) { 164 return var.getType() == Type.INT && typeSpec == Type.ENUM; 165 } 166 } 167