aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java254
1 files changed, 254 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java
new file mode 100644
index 000000000..b90c004b0
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java
@@ -0,0 +1,254 @@
+/*
+ * 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.gltrace.GLProtoBuf.GLMessage;
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function;
+import com.android.ide.eclipse.gltrace.format.GLAPISpec;
+import com.android.ide.eclipse.gltrace.format.GLMessageFormatter;
+import com.android.ide.eclipse.gltrace.model.GLCall;
+import com.android.ide.eclipse.gltrace.model.GLFrame;
+import com.android.ide.eclipse.gltrace.model.GLTrace;
+import com.android.ide.eclipse.gltrace.state.transforms.StateTransformFactory;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class TraceFileParserTask implements IRunnableWithProgress {
+ private static final TraceFileReader sReader = new TraceFileReader();
+
+ private static final GLMessageFormatter sGLMessageFormatter =
+ new GLMessageFormatter(GLAPISpec.getSpecs());
+
+ private String mTraceFilePath;
+ private RandomAccessFile mFile;
+
+ private List<GLCall> mGLCalls;
+ private Set<Integer> mGLContextIds;
+
+ private GLTrace mTrace;
+
+ /**
+ * Construct a GL Trace file parser.
+ * @param path path to trace file
+ */
+ public TraceFileParserTask(String path) {
+ try {
+ mFile = new RandomAccessFile(path, "r"); //$NON-NLS-1$
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ mTraceFilePath = path;
+ mGLCalls = new ArrayList<GLCall>();
+ mGLContextIds = new TreeSet<Integer>();
+ }
+
+ private void addMessage(int index, long traceFileOffset, GLMessage msg, long startTime) {
+ String formattedMsg;
+ try {
+ formattedMsg = sGLMessageFormatter.formatGLMessage(msg);
+ } catch (Exception e) {
+ formattedMsg = String.format("%s()", msg.getFunction().toString()); //$NON-NLS-1$
+ }
+
+ GLCall c = new GLCall(index,
+ startTime,
+ traceFileOffset,
+ formattedMsg,
+ msg.getFunction(),
+ msg.hasFb(),
+ msg.getContextId(),
+ msg.getDuration(),
+ msg.getThreadtime());
+
+ addProperties(c, msg);
+
+ try {
+ c.setStateTransformations(StateTransformFactory.getTransformsFor(msg));
+ } catch (Exception e) {
+ c.setStateTransformationCreationError(e.getMessage());
+ GlTracePlugin.getDefault().logMessage("Error while creating transformations for "
+ + c.toString() + ":");
+ GlTracePlugin.getDefault().logMessage(e.getMessage());
+ }
+
+ mGLCalls.add(c);
+ mGLContextIds.add(Integer.valueOf(c.getContextId()));
+ }
+
+ /** Save important values from the {@link GLMessage} in the {@link GLCall} as properties. */
+ private void addProperties(GLCall c, GLMessage msg) {
+ switch (msg.getFunction()) {
+ case glPushGroupMarkerEXT:
+ // void PushGroupMarkerEXT(sizei length, const char *marker);
+ // save the marker name
+ c.addProperty(GLCall.PROPERTY_MARKERNAME,
+ msg.getArgs(1).getCharValue(0).toStringUtf8());
+ break;
+ case glVertexAttribPointerData:
+ // void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type,
+ // GLboolean normalized, GLsizei stride, const GLvoid* ptr,
+ // int minIndex, int maxIndex)
+ c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_SIZE,
+ Integer.valueOf(msg.getArgs(1).getIntValue(0)));
+ c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_TYPE,
+ GLEnum.valueOf(msg.getArgs(2).getIntValue(0)));
+ c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_DATA,
+ msg.getArgs(5).getRawBytes(0).toByteArray());
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Parse the entire file and create a {@link GLTrace} object that can be retrieved
+ * using {@link #getTrace()}.
+ */
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException,
+ InterruptedException {
+ long fileLength;
+ try {
+ fileLength = mFile.length();
+ } catch (IOException e1) {
+ fileLength = 0;
+ }
+
+ monitor.beginTask("Parsing OpenGL Trace File",
+ fileLength > 0 ? 100 : IProgressMonitor.UNKNOWN);
+
+ List<GLFrame> glFrames = null;
+
+ try {
+ GLMessage msg = null;
+ int msgCount = 0;
+ long filePointer = mFile.getFilePointer();
+ int percentParsed = 0;
+
+ // counters that maintain some statistics about the trace messages
+ long minTraceStartTime = Long.MAX_VALUE;
+
+ while ((msg = sReader.getMessageAtOffset(mFile, -1)) != null) {
+ if (minTraceStartTime > msg.getStartTime()) {
+ minTraceStartTime = msg.getStartTime();
+ }
+
+ addMessage(msgCount, filePointer, msg, msg.getStartTime() - minTraceStartTime);
+
+ filePointer = mFile.getFilePointer();
+ msgCount++;
+
+ if (monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ if (fileLength > 0) {
+ int percentParsedNow = (int)((filePointer * 100) / fileLength);
+ monitor.worked(percentParsedNow - percentParsed);
+ percentParsed = percentParsedNow;
+ }
+ }
+
+ if (mGLContextIds.size() > 1) {
+ // if there are multiple contexts, then the calls may arrive at the
+ // host out of order. So we perform a sort based on the invocation time.
+ Collections.sort(mGLCalls, new Comparator<GLCall>() {
+ @Override
+ public int compare(GLCall c1, GLCall c2) {
+ long diff = (c1.getStartTime() - c2.getStartTime());
+
+ // We could return diff casted to an int. But in Java, casting
+ // from a long to an int truncates the bits and will not preserve
+ // the sign. So we resort to comparing the diff to 0 and returning
+ // the sign.
+ if (diff == 0) {
+ return 0;
+ } else if (diff > 0) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ });
+
+ // reassign indices after sorting
+ for (int i = 0; i < mGLCalls.size(); i++) {
+ mGLCalls.get(i).setIndex(i);
+ }
+ }
+
+ glFrames = createFrames(mGLCalls);
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ } finally {
+ try {
+ mFile.close();
+ } catch (IOException e) {
+ // ignore exception while closing file
+ }
+ monitor.done();
+ }
+
+ File f = new File(mTraceFilePath);
+ TraceFileInfo fileInfo = new TraceFileInfo(mTraceFilePath, f.length(), f.lastModified());
+ mTrace = new GLTrace(fileInfo, glFrames, mGLCalls, new ArrayList<Integer>(mGLContextIds));
+ }
+
+ /** Assign GL calls to GL Frames. */
+ private List<GLFrame> createFrames(List<GLCall> calls) {
+ List<GLFrame> glFrames = new ArrayList<GLFrame>();
+ int startCallIndex = 0;
+ int frameIndex = 0;
+
+ for (int i = 0; i < calls.size(); i++) {
+ GLCall c = calls.get(i);
+ if (c.getFunction() == Function.eglSwapBuffers) {
+ glFrames.add(new GLFrame(frameIndex, startCallIndex, i + 1));
+ startCallIndex = i + 1;
+ frameIndex++;
+ }
+ }
+
+ // assign left over calls at the end to the last frame
+ if (startCallIndex != mGLCalls.size()) {
+ glFrames.add(new GLFrame(frameIndex, startCallIndex, mGLCalls.size()));
+ }
+
+ return glFrames;
+ }
+
+ /**
+ * Retrieve the trace object constructed from messages in the trace file.
+ */
+ public GLTrace getTrace() {
+ return mTrace;
+ }
+}