diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java new file mode 100644 index 000000000..226d4831a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2012 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.editors; + +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function; +import com.android.ide.eclipse.gltrace.model.GLCall; +import com.android.ide.eclipse.gltrace.model.GLTrace; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +public class GLCallGroups { + /** + * A {@link GLCallNode} is a simple wrapper around a {@link GLCall} that + * adds the notion of hierarchy. + */ + public interface GLCallNode { + /** Does this call have child nodes? */ + boolean hasChildren(); + + /** Returns a list of child nodes of this call. */ + List<GLCallNode> getChildren(); + + /** Returns the {@link GLCall} that is wrapped by this node. */ + GLCall getCall(); + + /** Returns the parent of this node, the parent is null if this is a top level node */ + GLCallNode getParent(); + + /** Set the parent node. */ + void setParent(GLCallNode parent); + } + + private static class GLTreeNode implements GLCallNode { + private final GLCall mCall; + private GLCallNode mParent; + private List<GLCallNode> mGLCallNodes; + + public GLTreeNode(GLCall call) { + mCall = call; + mGLCallNodes = new ArrayList<GLCallNode>(); + } + + @Override + public boolean hasChildren() { + return true; + } + + @Override + public GLCallNode getParent() { + return mParent; + } + + @Override + public void setParent(GLCallNode parent) { + mParent = parent; + } + + @Override + public List<GLCallNode> getChildren() { + return mGLCallNodes; + } + + public void addChild(GLCallNode n) { + mGLCallNodes.add(n); + n.setParent(this); + } + + @Override + public GLCall getCall() { + return mCall; + } + } + + private static class GLLeafNode implements GLCallNode { + private final GLCall mCall; + private GLCallNode mParent; + + public GLLeafNode(GLCall call) { + mCall = call; + } + + @Override + public boolean hasChildren() { + return false; + } + + @Override + public List<GLCallNode> getChildren() { + return null; + } + + @Override + public GLCallNode getParent() { + return mParent; + } + + @Override + public void setParent(GLCallNode parent) { + mParent = parent; + } + + @Override + public GLCall getCall() { + return mCall; + } + } + + /** + * Impose a hierarchy on a list of {@link GLCall}'s based on the presence of + * {@link Function#glPushGroupMarkerEXT} and {@link Function#glPopGroupMarkerEXT} calls. + * Such a hierarchy is possible only if calls from a single context are considered. + * @param trace trace to look at + * @param start starting call index + * @param end ending call index + * @param contextToGroup context from which calls should be grouped. If no such context + * is present, then all calls in the given range will be returned back as a flat + * list. + * @return a tree structured list of {@link GLCallNode} objects + */ + public static List<GLCallNode> constructCallHierarchy(GLTrace trace, int start, int end, + int contextToGroup) { + if (trace == null) { + return Collections.emptyList(); + } + + if (contextToGroup < 0 || contextToGroup > trace.getContexts().size()) { + return flatHierarchy(trace, start, end); + } + + List<GLCall> calls = trace.getGLCalls(); + + Stack<GLTreeNode> hierarchyStack = new Stack<GLTreeNode>(); + List<GLCallNode> items = new ArrayList<GLCallNode>(); + + for (int i = start; i < end; i++) { + GLCall c = calls.get(i); + if (c.getContextId() != contextToGroup) { + // skip this call if it is not part of the context we need to display + continue; + } + + if (c.getFunction() == Function.glPushGroupMarkerEXT) { + GLTreeNode group = new GLTreeNode(c); + if (hierarchyStack.size() > 0) { + hierarchyStack.peek().addChild(group); + } else { + items.add(group); + } + hierarchyStack.push(group); + } else if (c.getFunction() == Function.glPopGroupMarkerEXT) { + if (hierarchyStack.size() > 0) { + hierarchyStack.pop(); + } else { + // FIXME: If we are attempting to pop from an empty stack, + // that implies that a push marker was seen in a prior frame + // (in a call before @start). In such a case, we simply continue + // adding further calls to the root of the hierarchy rather than + // searching backwards in the call list for the corresponding + // push markers. + items.add(new GLLeafNode(c)); + } + } else { + GLLeafNode leaf = new GLLeafNode(c); + if (hierarchyStack.size() > 0) { + hierarchyStack.peek().addChild(leaf); + } else { + items.add(leaf); + } + } + } + + return items; + } + + private static List<GLCallNode> flatHierarchy(GLTrace trace, int start, int end) { + List<GLCallNode> items = new ArrayList<GLCallNode>(); + + List<GLCall> calls = trace.getGLCalls(); + for (int i = start; i < end; i++) { + items.add(new GLLeafNode(calls.get(i))); + } + + return items; + } +} |