Home | History | Annotate | Download | only in format
      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 
     37     public GLMessageFormatter(Map<String, GLAPISpec> specs) {
     38         mAPISpecs = specs;
     39     }
     40 
     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 
     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 
     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 
     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 
     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 
    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 
    163     private boolean isEnumTypeWithIntData(DataType var, Type typeSpec) {
    164         return var.getType() == Type.INT && typeSpec == Type.ENUM;
    165     }
    166 }
    167