diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors')
6 files changed, 0 insertions, 2277 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/DurationMinimap.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/DurationMinimap.java deleted file mode 100644 index 9b4c57cad..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/DurationMinimap.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * 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 org.eclipse.jface.resource.FontRegistry; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.MouseAdapter; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseMoveListener; -import org.eclipse.swt.events.MouseTrackListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.FontData; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.widgets.Canvas; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; - -import java.util.ArrayList; -import java.util.List; - -public class DurationMinimap extends Canvas { - /** Default alpha value. */ - private static final int DEFAULT_ALPHA = 255; - - /** Alpha value for highlighting visible calls. */ - private static final int VISIBLE_CALLS_HIGHLIGHT_ALPHA = 50; - - /** Clamp call durations at this value. */ - private static final long CALL_DURATION_CLAMP = 20000; - - private static final String FONT_KEY = "default.font"; //$NON-NLS-1$ - - /** Scale font size by this amount to get the max display length of call duration. */ - private static final int MAX_DURATION_LENGTH_SCALE = 6; - - /** List of GL Calls in the trace. */ - private List<GLCall> mCalls; - - /** Number of GL contexts in the trace. */ - private int mContextCount; - - /** Starting call index of currently displayed frame. */ - private int mStartCallIndex; - - /** Ending call index of currently displayed frame. */ - private int mEndCallIndex; - - /** The top index that is currently visible in the table. */ - private int mVisibleCallTopIndex; - - /** The bottom index that is currently visible in the table. */ - private int mVisibleCallBottomIndex; - - private Color mBackgroundColor; - private Color mDurationLineColor; - private Color mGlDrawColor; - private Color mGlErrorColor; - private Color mContextHeaderColor; - private Color mVisibleCallsHighlightColor; - private Color mMouseMarkerColor; - - private FontRegistry mFontRegistry; - private int mFontWidth; - private int mFontHeight; - - // back buffers used for double buffering - private Image mBackBufferImage; - private GC mBackBufferGC; - - // mouse state - private boolean mMouseInSelf; - private int mMouseY; - - // helper object used to position various items on screen - private final PositionHelper mPositionHelper; - - public DurationMinimap(Composite parent, GLTrace trace) { - super(parent, SWT.NO_BACKGROUND); - - setInput(trace); - - initializeColors(); - initializeFonts(); - - mPositionHelper = new PositionHelper( - mFontHeight, - mContextCount, - mFontWidth * MAX_DURATION_LENGTH_SCALE, /* max display length for call. */ - CALL_DURATION_CLAMP /* max duration */); - - addPaintListener(new PaintListener() { - @Override - public void paintControl(PaintEvent e) { - draw(e.display, e.gc); - } - }); - - addListener(SWT.Resize, new Listener() { - @Override - public void handleEvent(Event event) { - controlResized(); - } - }); - - addMouseMoveListener(new MouseMoveListener() { - @Override - public void mouseMove(MouseEvent e) { - mouseMoved(e); - } - }); - - addMouseListener(new MouseAdapter() { - @Override - public void mouseUp(MouseEvent e) { - mouseClicked(e); - } - }); - - addMouseTrackListener(new MouseTrackListener() { - @Override - public void mouseHover(MouseEvent e) { - } - - @Override - public void mouseExit(MouseEvent e) { - mMouseInSelf = false; - redraw(); - } - - @Override - public void mouseEnter(MouseEvent e) { - mMouseInSelf = true; - redraw(); - } - }); - } - - public void setInput(GLTrace trace) { - if (trace != null) { - mCalls = trace.getGLCalls(); - mContextCount = trace.getContexts().size(); - } else { - mCalls = null; - mContextCount = 1; - } - } - - @Override - public void dispose() { - disposeColors(); - disposeBackBuffer(); - super.dispose(); - } - - private void initializeColors() { - mBackgroundColor = new Color(getDisplay(), 0x33, 0x33, 0x33); - mDurationLineColor = new Color(getDisplay(), 0x08, 0x51, 0x9c); - mGlDrawColor = new Color(getDisplay(), 0x6b, 0xae, 0xd6); - mContextHeaderColor = new Color(getDisplay(), 0xd1, 0xe5, 0xf0); - mVisibleCallsHighlightColor = new Color(getDisplay(), 0xcc, 0xcc, 0xcc); - mMouseMarkerColor = new Color(getDisplay(), 0xaa, 0xaa, 0xaa); - - mGlErrorColor = getDisplay().getSystemColor(SWT.COLOR_RED); - } - - private void disposeColors() { - mBackgroundColor.dispose(); - mDurationLineColor.dispose(); - mGlDrawColor.dispose(); - mContextHeaderColor.dispose(); - mVisibleCallsHighlightColor.dispose(); - mMouseMarkerColor.dispose(); - } - - private void initializeFonts() { - mFontRegistry = new FontRegistry(getDisplay()); - mFontRegistry.put(FONT_KEY, - new FontData[] { new FontData("Arial", 8, SWT.NORMAL) }); //$NON-NLS-1$ - - GC gc = new GC(getDisplay()); - gc.setFont(mFontRegistry.get(FONT_KEY)); - mFontWidth = gc.getFontMetrics().getAverageCharWidth(); - mFontHeight = gc.getFontMetrics().getHeight(); - gc.dispose(); - } - - private void initializeBackBuffer() { - Rectangle clientArea = getClientArea(); - - if (clientArea.width == 0 || clientArea.height == 0) { - mBackBufferImage = null; - mBackBufferGC = null; - return; - } - - mBackBufferImage = new Image(getDisplay(), - clientArea.width, - clientArea.height); - mBackBufferGC = new GC(mBackBufferImage); - } - - private void disposeBackBuffer() { - if (mBackBufferImage != null) { - mBackBufferImage.dispose(); - mBackBufferImage = null; - } - - if (mBackBufferGC != null) { - mBackBufferGC.dispose(); - mBackBufferGC = null; - } - } - - private void mouseMoved(MouseEvent e) { - mMouseY = e.y; - redraw(); - } - - private void mouseClicked(MouseEvent e) { - if (mMouseInSelf) { - int selIndex = mPositionHelper.getCallAt(mMouseY); - sendCallSelectedEvent(selIndex); - redraw(); - } - } - - private void draw(Display display, GC gc) { - if (mBackBufferImage == null) { - initializeBackBuffer(); - } - - if (mBackBufferImage == null) { - return; - } - - // draw contents onto the back buffer - drawBackground(mBackBufferGC, mBackBufferImage.getBounds()); - drawContextHeaders(mBackBufferGC); - drawCallDurations(mBackBufferGC); - drawVisibleCallHighlights(mBackBufferGC); - drawMouseMarkers(mBackBufferGC); - - // finally copy over the rendered back buffer onto screen - int width = getClientArea().width; - int height = getClientArea().height; - gc.drawImage(mBackBufferImage, - 0, 0, width, height, - 0, 0, width, height); - } - - private void drawBackground(GC gc, Rectangle bounds) { - gc.setBackground(mBackgroundColor); - gc.fillRectangle(bounds); - } - - private void drawContextHeaders(GC gc) { - if (mContextCount <= 1) { - return; - } - - gc.setForeground(mContextHeaderColor); - gc.setFont(mFontRegistry.get(FONT_KEY)); - for (int i = 0; i < mContextCount; i++) { - Point p = mPositionHelper.getHeaderLocation(i); - gc.drawText("CTX" + Integer.toString(i), p.x, p.y); - } - } - - /** Draw the call durations as a sequence of lines. - * - * Calls are arranged on the y-axis based on the sequence in which they were originally - * called by the application. If the display height is lesser than the number of calls, then - * not every call is shown - the calls are underscanned based the height of the display. - * - * The x-axis shows two pieces of information: the duration of the call, and the context - * in which the call was made. The duration controls how long the displayed line is, and - * the context controls the starting offset of the line. - */ - private void drawCallDurations(GC gc) { - if (mCalls == null || mCalls.size() < mEndCallIndex) { - return; - } - - gc.setBackground(mDurationLineColor); - - int callUnderScan = mPositionHelper.getCallUnderScanValue(); - for (int i = mStartCallIndex; i < mEndCallIndex; i += callUnderScan) { - boolean resetColor = false; - GLCall c = mCalls.get(i); - - long duration = c.getWallDuration(); - - if (c.hasErrors()) { - gc.setBackground(mGlErrorColor); - resetColor = true; - - // If the call has any errors, we want it to be visible in the minimap - // regardless of how long it took. - duration = mPositionHelper.getMaxDuration(); - } else if (c.getFunction() == Function.glDrawArrays - || c.getFunction() == Function.glDrawElements - || c.getFunction() == Function.eglSwapBuffers) { - gc.setBackground(mGlDrawColor); - resetColor = true; - - // render all draw calls & swap buffer at max length - duration = mPositionHelper.getMaxDuration(); - } - - Rectangle bounds = mPositionHelper.getDurationBounds( - i - mStartCallIndex, - c.getContextId(), - duration); - gc.fillRectangle(bounds); - - if (resetColor) { - gc.setBackground(mDurationLineColor); - } - } - } - - /** - * Draw a bounding box that highlights the currently visible range of calls in the - * {@link GLFunctionTraceViewer} table. - */ - private void drawVisibleCallHighlights(GC gc) { - gc.setAlpha(VISIBLE_CALLS_HIGHLIGHT_ALPHA); - gc.setBackground(mVisibleCallsHighlightColor); - gc.fillRectangle(mPositionHelper.getBoundsFramingCalls( - mVisibleCallTopIndex - mStartCallIndex, - mVisibleCallBottomIndex - mStartCallIndex)); - gc.setAlpha(DEFAULT_ALPHA); - } - - private void drawMouseMarkers(GC gc) { - if (!mMouseInSelf) { - return; - } - - if (mPositionHelper.getCallAt(mMouseY) < 0) { - return; - } - - gc.setForeground(mMouseMarkerColor); - gc.drawLine(0, mMouseY, getClientArea().width, mMouseY); - } - - private void controlResized() { - // regenerate back buffer on size changes - disposeBackBuffer(); - initializeBackBuffer(); - - redraw(); - } - - public int getMinimumWidth() { - return mPositionHelper.getMinimumWidth(); - } - - /** Set the GL Call start and end indices for currently displayed frame. */ - public void setCallRangeForCurrentFrame(int startCallIndex, int endCallIndex) { - mStartCallIndex = startCallIndex; - mEndCallIndex = endCallIndex; - mPositionHelper.updateCallDensity(mEndCallIndex - mStartCallIndex, getClientArea().height); - redraw(); - } - - /** - * Set the call range that is currently visible in the {@link GLFunctionTraceViewer} table. - * @param visibleTopIndex index of call currently visible at the top of the table. - * @param visibleBottomIndex index of call currently visible at the bottom of the table. - */ - public void setVisibleCallRange(int visibleTopIndex, int visibleBottomIndex) { - mVisibleCallTopIndex = visibleTopIndex; - mVisibleCallBottomIndex = visibleBottomIndex; - redraw(); - } - - public interface ICallSelectionListener { - void callSelected(int selectedCallIndex); - } - - private List<ICallSelectionListener> mListeners = new ArrayList<ICallSelectionListener>(); - - public void addCallSelectionListener(ICallSelectionListener l) { - mListeners.add(l); - } - - private void sendCallSelectedEvent(int selectedCall) { - for (ICallSelectionListener l : mListeners) { - l.callSelected(selectedCall); - } - } - - /** Utility class to help with the positioning and sizes of elements in the canvas. */ - private static class PositionHelper { - /** Left Margin after which duration lines are drawn. */ - private static final int LEFT_MARGIN = 5; - - /** Top margin after which header is drawn. */ - private static final int TOP_MARGIN = 5; - - /** # of pixels of padding between duration markers for different contexts. */ - private static final int CONTEXT_PADDING = 10; - - private final int mHeaderMargin; - private final int mContextCount; - private final int mMaxDurationLength; - private final long mMaxDuration; - private final double mScale; - - private int mCallCount; - private int mNumCallsPerPixel = 1; - - public PositionHelper(int fontHeight, int contextCount, - int maxDurationLength, long maxDuration) { - mContextCount = contextCount; - mMaxDurationLength = maxDurationLength; - mMaxDuration = maxDuration; - mScale = (double) maxDurationLength / maxDuration; - - // header region is present only there are multiple contexts - if (mContextCount > 1) { - mHeaderMargin = fontHeight * 3; - } else { - mHeaderMargin = 0; - } - } - - /** Get the minimum width of the canvas. */ - public int getMinimumWidth() { - return LEFT_MARGIN + (mMaxDurationLength + CONTEXT_PADDING) * mContextCount; - } - - /** Get the bounds for a call duration line. */ - public Rectangle getDurationBounds(int callIndex, int context, long duration) { - if (duration <= 0) { - duration = 1; - } else if (duration > mMaxDuration) { - duration = mMaxDuration; - } - - int x = LEFT_MARGIN + ((mMaxDurationLength + CONTEXT_PADDING) * context); - int y = (callIndex/mNumCallsPerPixel) + TOP_MARGIN + mHeaderMargin; - int w = (int) (duration * mScale); - int h = 1; - - return new Rectangle(x, y, w, h); - } - - public long getMaxDuration() { - return mMaxDuration; - } - - /** Get the bounds for calls spanning given range. */ - public Rectangle getBoundsFramingCalls(int startCallIndex, int endCallIndex) { - if (startCallIndex >= 0 && endCallIndex >= startCallIndex - && endCallIndex <= mCallCount) { - int x = LEFT_MARGIN; - int y = (startCallIndex/mNumCallsPerPixel) + TOP_MARGIN + mHeaderMargin; - int w = ((mMaxDurationLength + CONTEXT_PADDING) * mContextCount); - int h = (endCallIndex - startCallIndex)/mNumCallsPerPixel; - return new Rectangle(x, y, w, h); - } else { - return new Rectangle(0, 0, 0, 0); - } - } - - public Point getHeaderLocation(int context) { - int x = LEFT_MARGIN + ((mMaxDurationLength + CONTEXT_PADDING) * context); - return new Point(x, TOP_MARGIN); - } - - /** Update the call density based on the number of calls to be displayed and - * the available height to display them in. */ - public void updateCallDensity(int callCount, int displayHeight) { - mCallCount = callCount; - - if (displayHeight <= 0) { - displayHeight = callCount + 1; - } - - mNumCallsPerPixel = (callCount / displayHeight) + 1; - } - - /** Get the underscan value. In cases where there are more calls to be displayed - * than there are availble pixels, we only display 1 out of every underscan calls. */ - public int getCallUnderScanValue() { - return mNumCallsPerPixel; - } - - /** Get the index of the call at given y offset. */ - public int getCallAt(int y) { - if (!isWithinBounds(y)) { - return -1; - } - - Rectangle displayBounds = getBoundsFramingCalls(0, mCallCount); - return (y - displayBounds.y) * mNumCallsPerPixel; - } - - /** Does the provided y offset map to a valid call? */ - private boolean isWithinBounds(int y) { - Rectangle displayBounds = getBoundsFramingCalls(0, mCallCount); - if (y < displayBounds.y) { - return false; - } - - if (y > (displayBounds.y + displayBounds.height)) { - return false; - } - - return true; - } - } -} 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 deleted file mode 100644 index 226d4831a..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java deleted file mode 100644 index b809ddddf..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java +++ /dev/null @@ -1,984 +0,0 @@ -/* - * 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.editors; - -import com.android.ddmuilib.AbstractBufferFindTarget; -import com.android.ddmuilib.FindDialog; -import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function; -import com.android.ide.eclipse.gltrace.GlTracePlugin; -import com.android.ide.eclipse.gltrace.SwtUtils; -import com.android.ide.eclipse.gltrace.TraceFileParserTask; -import com.android.ide.eclipse.gltrace.editors.DurationMinimap.ICallSelectionListener; -import com.android.ide.eclipse.gltrace.editors.GLCallGroups.GLCallNode; -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.views.FrameSummaryViewPage; -import com.android.ide.eclipse.gltrace.views.detail.DetailsPage; -import com.google.common.base.Charsets; -import com.google.common.io.Files; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.ProgressMonitorDialog; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.CellLabelProvider; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.TreeViewerColumn; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerCell; -import org.eclipse.jface.viewers.ViewerFilter; -import org.eclipse.swt.SWT; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Scale; -import org.eclipse.swt.widgets.ScrollBar; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Spinner; -import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.ToolBar; -import org.eclipse.swt.widgets.ToolItem; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.swt.widgets.TreeItem; -import org.eclipse.ui.IActionBars; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorSite; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.IURIEditorInput; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.part.EditorPart; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** Display OpenGL function trace in a tabular view. */ -public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvider { - public static final String ID = "com.android.ide.eclipse.gltrace.GLFunctionTrace"; //$NON-NLS-1$ - - private static final String DEFAULT_FILTER_MESSAGE = "Filter list of OpenGL calls. Accepts Java regexes."; - private static final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$ - - private static Image sExpandAllIcon; - - private static String sLastExportedToFolder; - - private String mFilePath; - private Scale mFrameSelectionScale; - private Spinner mFrameSelectionSpinner; - - private GLTrace mTrace; - - private TreeViewer mFrameTreeViewer; - private List<GLCallNode> mTreeViewerNodes; - - private Text mFilterText; - private GLCallFilter mGLCallFilter; - - private Color mGldrawTextColor; - private Color mGlCallErrorColor; - - /** - * Job to refresh the tree view & frame summary view. - * - * When the currently displayed frame is changed, either via the {@link #mFrameSelectionScale} - * or via {@link #mFrameSelectionSpinner}, we need to update the displayed tree of calls for - * that frame, and the frame summary view. Both these operations need to happen on the UI - * thread, but are time consuming. This works out ok if the frame selection is not changing - * rapidly (i.e., when the spinner or scale is moved to the target frame in a single action). - * However, if the spinner is constantly pressed, then the user is scrolling through a sequence - * of frames, and rather than refreshing the details for each of the intermediate frames, - * we create a job to refresh the details and schedule the job after a short interval - * {@link #TREE_REFRESH_INTERVAL}. This allows us to stay responsive to the spinner/scale, - * and not do the costly refresh for each of the intermediate frames. - */ - private Job mTreeRefresherJob; - private final Object mTreeRefresherLock = new Object(); - private static final int TREE_REFRESH_INTERVAL_MS = 250; - - private int mCurrentFrame; - - // Currently displayed frame's start and end call indices. - private int mCallStartIndex; - private int mCallEndIndex; - - private DurationMinimap mDurationMinimap; - private ScrollBar mVerticalScrollBar; - - private Combo mContextSwitchCombo; - private boolean mShowContextSwitcher; - private int mCurrentlyDisplayedContext = -1; - - private StateViewPage mStateViewPage; - private FrameSummaryViewPage mFrameSummaryViewPage; - private DetailsPage mDetailsPage; - - private ToolItem mExpandAllToolItem; - private ToolItem mCollapseAllToolItem; - private ToolItem mSaveAsToolItem; - - public GLFunctionTraceViewer() { - mGldrawTextColor = Display.getDefault().getSystemColor(SWT.COLOR_BLUE); - mGlCallErrorColor = Display.getDefault().getSystemColor(SWT.COLOR_RED); - } - - @Override - public void doSave(IProgressMonitor monitor) { - } - - @Override - public void doSaveAs() { - } - - @Override - public void init(IEditorSite site, IEditorInput input) throws PartInitException { - // we use a IURIEditorInput to allow opening files not within the workspace - if (!(input instanceof IURIEditorInput)) { - throw new PartInitException("GL Function Trace View: unsupported input type."); - } - - setSite(site); - setInput(input); - mFilePath = ((IURIEditorInput) input).getURI().getPath(); - - // set the editor part name to be the name of the file. - File f = new File(mFilePath); - setPartName(f.getName()); - } - - @Override - public boolean isDirty() { - return false; - } - - @Override - public boolean isSaveAsAllowed() { - return false; - } - - @Override - public void createPartControl(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(1, false)); - GridData gd = new GridData(GridData.FILL_BOTH); - c.setLayoutData(gd); - - setInput(parent.getShell(), mFilePath); - - createFrameSelectionControls(c); - createOptionsBar(c); - createFrameTraceView(c); - - getSite().setSelectionProvider(mFrameTreeViewer); - - IActionBars actionBars = getEditorSite().getActionBars(); - actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), - new Action("Copy") { - @Override - public void run() { - copySelectionToClipboard(); - } - }); - - actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), - new Action("Select All") { - @Override - public void run() { - selectAll(); - } - }); - - actionBars.setGlobalActionHandler(ActionFactory.FIND.getId(), - new Action("Find") { - @Override - public void run() { - showFindDialog(); - } - }); - } - - public void setInput(Shell shell, String tracePath) { - ProgressMonitorDialog dlg = new ProgressMonitorDialog(shell); - TraceFileParserTask parser = new TraceFileParserTask(mFilePath); - try { - dlg.run(true, true, parser); - } catch (InvocationTargetException e) { - // exception while parsing, display error to user - MessageDialog.openError(shell, - "Error parsing OpenGL Trace File", - e.getCause().getMessage()); - return; - } catch (InterruptedException e) { - // operation canceled by user, just return - return; - } - - mTrace = parser.getTrace(); - mShowContextSwitcher = (mTrace == null) ? false : mTrace.getContexts().size() > 1; - if (mStateViewPage != null) { - mStateViewPage.setInput(mTrace); - } - if (mFrameSummaryViewPage != null) { - mFrameSummaryViewPage.setInput(mTrace); - } - if (mDetailsPage != null) { - mDetailsPage.setInput(mTrace); - } - if (mDurationMinimap != null) { - mDurationMinimap.setInput(mTrace); - } - - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - refreshUI(); - } - }); - } - - private void refreshUI() { - if (mTrace == null || mTrace.getGLCalls().size() == 0) { - setFrameCount(0); - return; - } - - setFrameCount(mTrace.getFrames().size()); - selectFrame(1); - } - - private void createFrameSelectionControls(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(3, false)); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - c.setLayoutData(gd); - - Label l = new Label(c, SWT.NONE); - l.setText("Select Frame:"); - - mFrameSelectionScale = new Scale(c, SWT.HORIZONTAL); - mFrameSelectionScale.setMinimum(1); - mFrameSelectionScale.setMaximum(1); - mFrameSelectionScale.setSelection(0); - gd = new GridData(GridData.FILL_HORIZONTAL); - mFrameSelectionScale.setLayoutData(gd); - - mFrameSelectionScale.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - int selectedFrame = mFrameSelectionScale.getSelection(); - mFrameSelectionSpinner.setSelection(selectedFrame); - selectFrame(selectedFrame); - } - }); - - mFrameSelectionSpinner = new Spinner(c, SWT.BORDER); - gd = new GridData(); - // width to hold atleast 6 digits - gd.widthHint = SwtUtils.getApproximateFontWidth(mFrameSelectionSpinner) * 6; - mFrameSelectionSpinner.setLayoutData(gd); - - mFrameSelectionSpinner.setMinimum(1); - mFrameSelectionSpinner.setMaximum(1); - mFrameSelectionSpinner.setSelection(0); - mFrameSelectionSpinner.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - int selectedFrame = mFrameSelectionSpinner.getSelection(); - mFrameSelectionScale.setSelection(selectedFrame); - selectFrame(selectedFrame); - } - }); - } - - private void setFrameCount(int nFrames) { - boolean en = nFrames > 0; - mFrameSelectionScale.setEnabled(en); - mFrameSelectionSpinner.setEnabled(en); - - mFrameSelectionScale.setMaximum(nFrames); - mFrameSelectionSpinner.setMaximum(nFrames); - } - - private void selectFrame(int selectedFrame) { - mFrameSelectionScale.setSelection(selectedFrame); - mFrameSelectionSpinner.setSelection(selectedFrame); - - synchronized (mTreeRefresherLock) { - if (mTrace != null) { - GLFrame f = mTrace.getFrame(selectedFrame - 1); - mCallStartIndex = f.getStartIndex(); - mCallEndIndex = f.getEndIndex(); - } else { - mCallStartIndex = mCallEndIndex = 0; - } - - mCurrentFrame = selectedFrame - 1; - - scheduleNewRefreshJob(); - } - - // update minimap view - mDurationMinimap.setCallRangeForCurrentFrame(mCallStartIndex, mCallEndIndex); - } - - /** - * Show only calls from the given context - * @param context context id whose calls should be displayed. Illegal values will result in - * calls from all contexts being displayed. - */ - private void selectContext(int context) { - if (mCurrentlyDisplayedContext == context) { - return; - } - - synchronized (mTreeRefresherLock) { - mCurrentlyDisplayedContext = context; - scheduleNewRefreshJob(); - } - } - - private void scheduleNewRefreshJob() { - if (mTreeRefresherJob != null) { - return; - } - - mTreeRefresherJob = new Job("Refresh GL Trace View Tree") { - @Override - protected IStatus run(IProgressMonitor monitor) { - final int start, end, context; - - synchronized (mTreeRefresherLock) { - start = mCallStartIndex; - end = mCallEndIndex; - context = mCurrentlyDisplayedContext; - - mTreeRefresherJob = null; - } - - // update tree view in the editor - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - refreshTree(start, end, context); - - // update the frame summary view - if (mFrameSummaryViewPage != null) { - mFrameSummaryViewPage.setSelectedFrame(mCurrentFrame); - } - } - }); - return Status.OK_STATUS; - } - }; - mTreeRefresherJob.setPriority(Job.SHORT); - mTreeRefresherJob.schedule(TREE_REFRESH_INTERVAL_MS); - } - - private void refreshTree(int startCallIndex, int endCallIndex, int contextToDisplay) { - mTreeViewerNodes = GLCallGroups.constructCallHierarchy(mTrace, - startCallIndex, endCallIndex, - contextToDisplay); - mFrameTreeViewer.setInput(mTreeViewerNodes); - mFrameTreeViewer.refresh(); - mFrameTreeViewer.expandAll(); - } - - private void createOptionsBar(Composite parent) { - int numColumns = mShowContextSwitcher ? 4 : 3; - - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(numColumns, false)); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - c.setLayoutData(gd); - - Label l = new Label(c, SWT.NONE); - l.setText("Filter:"); - - mFilterText = new Text(c, SWT.BORDER | SWT.ICON_SEARCH | SWT.SEARCH | SWT.ICON_CANCEL); - mFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mFilterText.setMessage(DEFAULT_FILTER_MESSAGE); - mFilterText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - updateAppliedFilters(); - } - }); - - if (mShowContextSwitcher) { - mContextSwitchCombo = new Combo(c, SWT.BORDER | SWT.READ_ONLY); - - // Setup the combo such that "All Contexts" is the first item, - // and then we have an item for each context. - mContextSwitchCombo.add("All Contexts"); - mContextSwitchCombo.select(0); - mCurrentlyDisplayedContext = -1; // showing all contexts - for (int i = 0; i < mTrace.getContexts().size(); i++) { - mContextSwitchCombo.add("Context " + i); - } - - mContextSwitchCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - selectContext(mContextSwitchCombo.getSelectionIndex() - 1); - } - }); - } else { - mCurrentlyDisplayedContext = 0; - } - - ToolBar toolBar = new ToolBar(c, SWT.FLAT | SWT.BORDER); - - mExpandAllToolItem = new ToolItem(toolBar, SWT.PUSH); - mExpandAllToolItem.setToolTipText("Expand All"); - if (sExpandAllIcon == null) { - ImageDescriptor id = GlTracePlugin.getImageDescriptor("/icons/expandall.png"); - sExpandAllIcon = id.createImage(); - } - if (sExpandAllIcon != null) { - mExpandAllToolItem.setImage(sExpandAllIcon); - } - - mCollapseAllToolItem = new ToolItem(toolBar, SWT.PUSH); - mCollapseAllToolItem.setToolTipText("Collapse All"); - mCollapseAllToolItem.setImage( - PlatformUI.getWorkbench().getSharedImages().getImage( - ISharedImages.IMG_ELCL_COLLAPSEALL)); - - mSaveAsToolItem = new ToolItem(toolBar, SWT.PUSH); - mSaveAsToolItem.setToolTipText("Export Trace"); - mSaveAsToolItem.setImage( - PlatformUI.getWorkbench().getSharedImages().getImage( - ISharedImages.IMG_ETOOL_SAVEAS_EDIT)); - - SelectionListener toolbarSelectionListener = new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (e.getSource() == mCollapseAllToolItem) { - setTreeItemsExpanded(false); - } else if (e.getSource() == mExpandAllToolItem) { - setTreeItemsExpanded(true); - } else if (e.getSource() == mSaveAsToolItem) { - exportTrace(); - } - } - }; - mExpandAllToolItem.addSelectionListener(toolbarSelectionListener); - mCollapseAllToolItem.addSelectionListener(toolbarSelectionListener); - mSaveAsToolItem.addSelectionListener(toolbarSelectionListener); - } - - private void updateAppliedFilters() { - mGLCallFilter.setFilters(mFilterText.getText().trim()); - mFrameTreeViewer.refresh(); - } - - private void createFrameTraceView(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(2, false)); - GridData gd = new GridData(GridData.FILL_BOTH); - c.setLayoutData(gd); - - final Tree tree = new Tree(c, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI); - gd = new GridData(GridData.FILL_BOTH); - tree.setLayoutData(gd); - tree.setLinesVisible(true); - tree.setHeaderVisible(true); - - mFrameTreeViewer = new TreeViewer(tree); - CellLabelProvider labelProvider = new GLFrameLabelProvider(); - - // column showing the GL context id - TreeViewerColumn tvc = new TreeViewerColumn(mFrameTreeViewer, SWT.NONE); - tvc.setLabelProvider(labelProvider); - TreeColumn column = tvc.getColumn(); - column.setText("Function"); - column.setWidth(500); - - // column showing the GL function duration (wall clock time) - tvc = new TreeViewerColumn(mFrameTreeViewer, SWT.NONE); - tvc.setLabelProvider(labelProvider); - column = tvc.getColumn(); - column.setText("Wall Time (ns)"); - column.setWidth(150); - column.setAlignment(SWT.RIGHT); - - // column showing the GL function duration (thread time) - tvc = new TreeViewerColumn(mFrameTreeViewer, SWT.NONE); - tvc.setLabelProvider(labelProvider); - column = tvc.getColumn(); - column.setText("Thread Time (ns)"); - column.setWidth(150); - column.setAlignment(SWT.RIGHT); - - mFrameTreeViewer.setContentProvider(new GLFrameContentProvider()); - - mGLCallFilter = new GLCallFilter(); - mFrameTreeViewer.addFilter(mGLCallFilter); - - // when the control is resized, give all the additional space - // to the function name column. - tree.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - int w = mFrameTreeViewer.getTree().getClientArea().width; - if (w > 200) { - mFrameTreeViewer.getTree().getColumn(2).setWidth(100); - mFrameTreeViewer.getTree().getColumn(1).setWidth(100); - mFrameTreeViewer.getTree().getColumn(0).setWidth(w - 200); - } - } - }); - - mDurationMinimap = new DurationMinimap(c, mTrace); - gd = new GridData(GridData.FILL_VERTICAL); - gd.widthHint = gd.minimumWidth = mDurationMinimap.getMinimumWidth(); - mDurationMinimap.setLayoutData(gd); - mDurationMinimap.addCallSelectionListener(new ICallSelectionListener() { - @Override - public void callSelected(int selectedCallIndex) { - if (selectedCallIndex > 0 && selectedCallIndex < mTreeViewerNodes.size()) { - TreeItem item = tree.getItem(selectedCallIndex); - tree.select(item); - tree.setTopItem(item); - } - } - }); - - mVerticalScrollBar = tree.getVerticalBar(); - mVerticalScrollBar.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - updateVisibleRange(); - } - }); - } - - private void updateVisibleRange() { - int visibleCallTopIndex = mCallStartIndex; - int visibleCallBottomIndex = mCallEndIndex; - - if (mVerticalScrollBar.isEnabled()) { - int selection = mVerticalScrollBar.getSelection(); - int thumb = mVerticalScrollBar.getThumb(); - int max = mVerticalScrollBar.getMaximum(); - - // from the scrollbar values, compute the visible fraction - double top = (double) selection / max; - double bottom = (double) (selection + thumb) / max; - - // map the fraction to the call indices - int range = mCallEndIndex - mCallStartIndex; - visibleCallTopIndex = mCallStartIndex + (int) Math.floor(range * top); - visibleCallBottomIndex = mCallStartIndex + (int) Math.ceil(range * bottom); - } - - mDurationMinimap.setVisibleCallRange(visibleCallTopIndex, visibleCallBottomIndex); - } - - @Override - public void setFocus() { - mFrameTreeViewer.getTree().setFocus(); - } - - private static class GLFrameContentProvider implements ITreeContentProvider { - @Override - public void dispose() { - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - @Override - public Object[] getElements(Object inputElement) { - return getChildren(inputElement); - } - - @Override - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof List<?>) { - return ((List<?>) parentElement).toArray(); - } - - if (!(parentElement instanceof GLCallNode)) { - return null; - } - - GLCallNode parent = (GLCallNode) parentElement; - if (parent.hasChildren()) { - return parent.getChildren().toArray(); - } else { - return new Object[0]; - } - } - - @Override - public Object getParent(Object element) { - if (!(element instanceof GLCallNode)) { - return null; - } - - return ((GLCallNode) element).getParent(); - } - - @Override - public boolean hasChildren(Object element) { - if (!(element instanceof GLCallNode)) { - return false; - } - - return ((GLCallNode) element).hasChildren(); - } - } - - private class GLFrameLabelProvider extends ColumnLabelProvider { - @Override - public void update(ViewerCell cell) { - Object element = cell.getElement(); - if (!(element instanceof GLCallNode)) { - return; - } - - GLCall c = ((GLCallNode) element).getCall(); - - if (c.getFunction() == Function.glDrawArrays - || c.getFunction() == Function.glDrawElements) { - cell.setForeground(mGldrawTextColor); - } - - if (c.hasErrors()) { - cell.setForeground(mGlCallErrorColor); - } - - cell.setText(getColumnText(c, cell.getColumnIndex())); - } - - private String getColumnText(GLCall c, int columnIndex) { - switch (columnIndex) { - case 0: - if (c.getFunction() == Function.glPushGroupMarkerEXT) { - Object marker = c.getProperty(GLCall.PROPERTY_MARKERNAME); - if (marker instanceof String) { - return ((String) marker); - } - } - return c.toString(); - case 1: - return formatDuration(c.getWallDuration()); - case 2: - return formatDuration(c.getThreadDuration()); - default: - return Integer.toString(c.getContextId()); - } - } - - private String formatDuration(int time) { - // Max duration is in the 10s of milliseconds, so xx,xxx,xxx ns - // So we require a format specifier that is 10 characters wide - return String.format("%,10d", time); //$NON-NLS-1$ - } - } - - private static class GLCallFilter extends ViewerFilter { - private final List<Pattern> mPatterns = new ArrayList<Pattern>(); - - public void setFilters(String filter) { - mPatterns.clear(); - - // split the user input into multiple regexes - // we assume that the regexes are OR'ed together i.e., all text that matches - // any one of the regexes will be displayed - for (String regex : filter.split(" ")) { - mPatterns.add(Pattern.compile(regex, Pattern.CASE_INSENSITIVE)); - } - } - - @Override - public boolean select(Viewer viewer, Object parentElement, Object element) { - if (!(element instanceof GLCallNode)) { - return true; - } - - String text = getTextUnderNode((GLCallNode) element); - - if (mPatterns.size() == 0) { - // match if there are no regex filters - return true; - } - - for (Pattern p : mPatterns) { - Matcher matcher = p.matcher(text); - if (matcher.find()) { - // match if atleast one of the regexes matches this text - return true; - } - } - - return false; - } - - /** Obtain a string representation of all functions under a given tree node. */ - private String getTextUnderNode(GLCallNode element) { - String func = element.getCall().getFunction().toString(); - if (!element.hasChildren()) { - return func; - } - - StringBuilder sb = new StringBuilder(100); - sb.append(func); - - for (GLCallNode child : element.getChildren()) { - sb.append(getTextUnderNode(child)); - } - - return sb.toString(); - } - } - - @Override - public void addSelectionChangedListener(ISelectionChangedListener listener) { - if (mFrameTreeViewer != null) { - mFrameTreeViewer.addSelectionChangedListener(listener); - } - } - - @Override - public ISelection getSelection() { - if (mFrameTreeViewer != null) { - return mFrameTreeViewer.getSelection(); - } else { - return null; - } - } - - @Override - public void removeSelectionChangedListener(ISelectionChangedListener listener) { - if (mFrameTreeViewer != null) { - mFrameTreeViewer.removeSelectionChangedListener(listener); - } - } - - @Override - public void setSelection(ISelection selection) { - if (mFrameTreeViewer != null) { - mFrameTreeViewer.setSelection(selection); - } - } - - public GLTrace getTrace() { - return mTrace; - } - - public StateViewPage getStateViewPage() { - if (mStateViewPage == null) { - mStateViewPage = new StateViewPage(mTrace); - } - - return mStateViewPage; - } - - public FrameSummaryViewPage getFrameSummaryViewPage() { - if (mFrameSummaryViewPage == null) { - mFrameSummaryViewPage = new FrameSummaryViewPage(mTrace); - } - - return mFrameSummaryViewPage; - } - - public DetailsPage getDetailsPage() { - if (mDetailsPage == null) { - mDetailsPage = new DetailsPage(mTrace); - } - - return mDetailsPage; - } - - private void copySelectionToClipboard() { - if (mFrameTreeViewer == null || mFrameTreeViewer.getTree().isDisposed()) { - return; - } - - StringBuilder sb = new StringBuilder(); - - for (TreeItem it: mFrameTreeViewer.getTree().getSelection()) { - Object data = it.getData(); - if (data instanceof GLCallNode) { - sb.append(((GLCallNode) data).getCall()); - sb.append(NEWLINE); - } - } - - if (sb.length() > 0) { - Clipboard cb = new Clipboard(Display.getDefault()); - cb.setContents( - new Object[] { sb.toString() }, - new Transfer[] { TextTransfer.getInstance() }); - cb.dispose(); - } - } - - private void selectAll() { - if (mFrameTreeViewer == null || mFrameTreeViewer.getTree().isDisposed()) { - return; - } - - mFrameTreeViewer.getTree().selectAll(); - } - - private void exportTrace() { - if (mFrameTreeViewer == null || mFrameTreeViewer.getTree().isDisposed()) { - return; - } - - if (mCallEndIndex == 0) { - return; - } - - FileDialog fd = new FileDialog(mFrameTreeViewer.getTree().getShell(), SWT.SAVE); - fd.setFilterExtensions(new String[] { "*.txt" }); - if (sLastExportedToFolder != null) { - fd.setFilterPath(sLastExportedToFolder); - } - - String path = fd.open(); - if (path == null) { - return; - } - - File f = new File(path); - sLastExportedToFolder = f.getParent(); - try { - exportFrameTo(f); - } catch (IOException e) { - ErrorDialog.openError(mFrameTreeViewer.getTree().getShell(), - "Export trace file.", - "Unexpected error exporting trace file.", - new Status(Status.ERROR, GlTracePlugin.PLUGIN_ID, e.toString())); - } - } - - private void exportFrameTo(File f) throws IOException { - String glCalls = serializeGlCalls(mTrace.getGLCalls(), mCallStartIndex, mCallEndIndex); - Files.write(glCalls, f, Charsets.UTF_8); - } - - private String serializeGlCalls(List<GLCall> glCalls, int start, int end) { - StringBuilder sb = new StringBuilder(); - while (start < end) { - sb.append(glCalls.get(start).toString()); - sb.append("\n"); //$NON-NLS-1$ - start++; - } - - return sb.toString(); - } - - private void setTreeItemsExpanded(boolean expand) { - if (mFrameTreeViewer == null || mFrameTreeViewer.getTree().isDisposed()) { - return; - } - - if (expand) { - mFrameTreeViewer.expandAll(); - } else { - mFrameTreeViewer.collapseAll(); - } - } - - private class TraceViewerFindTarget extends AbstractBufferFindTarget { - @Override - public int getItemCount() { - return mFrameTreeViewer.getTree().getItemCount(); - } - - @Override - public String getItem(int index) { - Object data = mFrameTreeViewer.getTree().getItem(index).getData(); - if (data instanceof GLCallNode) { - return ((GLCallNode) data).getCall().toString(); - } - return null; - } - - @Override - public void selectAndReveal(int index) { - Tree t = mFrameTreeViewer.getTree(); - t.deselectAll(); - t.select(t.getItem(index)); - t.showSelection(); - } - - @Override - public int getStartingIndex() { - return 0; - } - }; - - private FindDialog mFindDialog; - private TraceViewerFindTarget mFindTarget = new TraceViewerFindTarget(); - - private void showFindDialog() { - if (mFindDialog != null) { - // the dialog is already displayed - return; - } - - mFindDialog = new FindDialog(Display.getDefault().getActiveShell(), - mFindTarget, - FindDialog.FIND_NEXT_ID); - mFindDialog.open(); // blocks until find dialog is closed - mFindDialog = null; - } - - public String getInputPath() { - return mFilePath; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateContentProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateContentProvider.java deleted file mode 100644 index 7bff168fc..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateContentProvider.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.editors; - -import com.android.ide.eclipse.gltrace.state.GLCompositeProperty; -import com.android.ide.eclipse.gltrace.state.GLListProperty; -import com.android.ide.eclipse.gltrace.state.GLSparseArrayProperty; -import com.android.ide.eclipse.gltrace.state.IGLProperty; - -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.Viewer; - -public class StateContentProvider implements ITreeContentProvider { - @Override - public void dispose() { - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - @Override - public Object[] getElements(Object inputElement) { - return getChildren(inputElement); - } - - @Override - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof GLListProperty) { - return ((GLListProperty) parentElement).getList().toArray(); - } - - if (parentElement instanceof GLCompositeProperty) { - return ((GLCompositeProperty) parentElement).getProperties().toArray(); - } - - if (parentElement instanceof GLSparseArrayProperty) { - return ((GLSparseArrayProperty) parentElement).getValues().toArray(); - } - - return null; - } - - @Override - public Object getParent(Object element) { - if (element instanceof IGLProperty) { - return ((IGLProperty) element).getParent(); - } - - return null; - } - - @Override - public boolean hasChildren(Object element) { - if (element instanceof IGLProperty) { - return ((IGLProperty) element).isComposite(); - } - - return false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateLabelProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateLabelProvider.java deleted file mode 100644 index e37ea77fd..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateLabelProvider.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.editors; - -import com.android.ide.eclipse.gltrace.state.GLListProperty; -import com.android.ide.eclipse.gltrace.state.GLSparseArrayProperty; -import com.android.ide.eclipse.gltrace.state.GLStateType; -import com.android.ide.eclipse.gltrace.state.IGLProperty; - -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.ViewerCell; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.widgets.Display; - -import java.util.Set; - -public class StateLabelProvider extends ColumnLabelProvider { - private Set<IGLProperty> mChangedProperties; - - private Color mHighlightForegroundColor; - private Color mNormalForegroundColor; - - public StateLabelProvider() { - mHighlightForegroundColor = Display.getDefault().getSystemColor(SWT.COLOR_BLUE); - mNormalForegroundColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK); - } - - public String getColumnText(IGLProperty property, int columnIndex) { - switch (columnIndex) { - case 0: - return getName(property); - case 1: - return getValue(property); - default: - return ""; - } - } - - private String getValue(IGLProperty element) { - return element.getStringValue(); - } - - private String getName(IGLProperty element) { - IGLProperty parent = element.getParent(); - if (parent instanceof GLListProperty) { - // For members of list, use the index in the list as the name as opposed to - // the property type - int index = ((GLListProperty) parent).indexOf(element); - if (element.getType() == GLStateType.GL_STATE_ES1) { - return String.format("Context %d (ES1)", index); - } else if (element.getType() == GLStateType.GL_STATE_ES2) { - return String.format("Context %d (ES2)", index); - } else { - return Integer.toString(index); - } - } else if (parent instanceof GLSparseArrayProperty) { - // For members of sparse array, use the key as the name as opposed to - // the property type - int index = ((GLSparseArrayProperty) parent).keyFor(element); - return Integer.toString(index); - } - - return element.getType().getDescription(); - } - - @Override - public void update(ViewerCell cell) { - Object element = cell.getElement(); - if (!(element instanceof IGLProperty)) { - return; - } - - IGLProperty prop = (IGLProperty) element; - - String text = getColumnText(prop, cell.getColumnIndex()); - cell.setText(text); - - if (mChangedProperties != null && mChangedProperties.contains(prop)) { - cell.setForeground(mHighlightForegroundColor); - } else { - cell.setForeground(mNormalForegroundColor); - } - } - - public void setChangedProperties(Set<IGLProperty> changedProperties) { - mChangedProperties = changedProperties; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateViewPage.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateViewPage.java deleted file mode 100644 index faa9561cb..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateViewPage.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * 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.editors; - -import com.android.ide.eclipse.gltrace.GlTracePlugin; -import com.android.ide.eclipse.gltrace.editors.GLCallGroups.GLCallNode; -import com.android.ide.eclipse.gltrace.model.GLCall; -import com.android.ide.eclipse.gltrace.model.GLTrace; -import com.android.ide.eclipse.gltrace.state.GLState; -import com.android.ide.eclipse.gltrace.state.IGLProperty; -import com.android.ide.eclipse.gltrace.state.StatePrettyPrinter; -import com.android.ide.eclipse.gltrace.state.transforms.IStateTransform; -import com.google.common.base.Charsets; -import com.google.common.io.Files; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.ILock; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.IToolBarManager; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.layout.GridDataFactory; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.jface.viewers.TreeSelection; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.part.IPageSite; -import org.eclipse.ui.part.Page; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * A tree view of the OpenGL state. It listens to the current GLCall that is selected - * in the Function Trace view, and updates its view to reflect the state as of the selected call. - */ -public class StateViewPage extends Page implements ISelectionListener, ISelectionProvider { - public static final String ID = "com.android.ide.eclipse.gltrace.views.GLState"; //$NON-NLS-1$ - private static String sLastUsedPath; - private static final ILock sGlStateLock = Job.getJobManager().newLock(); - - private GLTrace mTrace; - private List<GLCall> mGLCalls; - - /** OpenGL State as of call {@link #mCurrentStateIndex}. */ - private IGLProperty mState; - private int mCurrentStateIndex; - - private String[] TREE_PROPERTIES = { "Name", "Value" }; - private TreeViewer mTreeViewer; - private StateLabelProvider mLabelProvider; - - public StateViewPage(GLTrace trace) { - setInput(trace); - } - - public void setInput(GLTrace trace) { - mTrace = trace; - if (trace != null) { - mGLCalls = trace.getGLCalls(); - } else { - mGLCalls = null; - } - - mState = GLState.createDefaultState(); - mCurrentStateIndex = -1; - - if (mTreeViewer != null) { - mTreeViewer.setInput(mState); - mTreeViewer.refresh(); - } - } - - @Override - public void createControl(Composite parent) { - final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.H_SCROLL | SWT.V_SCROLL); - GridDataFactory.fillDefaults().grab(true, true).applyTo(tree); - - tree.setHeaderVisible(true); - tree.setLinesVisible(true); - tree.setLayoutData(new GridData(GridData.FILL_BOTH)); - - TreeColumn col1 = new TreeColumn(tree, SWT.LEFT); - col1.setText(TREE_PROPERTIES[0]); - col1.setWidth(200); - - TreeColumn col2 = new TreeColumn(tree, SWT.LEFT); - col2.setText(TREE_PROPERTIES[1]); - col2.setWidth(200); - - mTreeViewer = new TreeViewer(tree); - mTreeViewer.setContentProvider(new StateContentProvider()); - mLabelProvider = new StateLabelProvider(); - mTreeViewer.setLabelProvider(mLabelProvider); - mTreeViewer.setInput(mState); - mTreeViewer.refresh(); - - final IToolBarManager manager = getSite().getActionBars().getToolBarManager(); - manager.add(new Action("Save to File", - PlatformUI.getWorkbench().getSharedImages().getImageDescriptor( - ISharedImages.IMG_ETOOL_SAVEAS_EDIT)) { - @Override - public void run() { - saveCurrentState(); - } - }); - } - - private void saveCurrentState() { - final Shell shell = mTreeViewer.getTree().getShell(); - FileDialog fd = new FileDialog(shell, SWT.SAVE); - fd.setFilterExtensions(new String[] { "*.txt" }); - if (sLastUsedPath != null) { - fd.setFilterPath(sLastUsedPath); - } - - String path = fd.open(); - if (path == null) { - return; - } - - File f = new File(path); - sLastUsedPath = f.getParent(); - - // export state to f - StatePrettyPrinter pp = new StatePrettyPrinter(); - synchronized (sGlStateLock) { - mState.prettyPrint(pp); - } - - try { - Files.write(pp.toString(), f, Charsets.UTF_8); - } catch (IOException e) { - ErrorDialog.openError(shell, - "Export GL State", - "Unexpected error while writing GL state to file.", - new Status(Status.ERROR, GlTracePlugin.PLUGIN_ID, e.toString())); - } - } - - @Override - public void init(IPageSite pageSite) { - super.init(pageSite); - pageSite.getPage().addSelectionListener(this); - } - - @Override - public void dispose() { - getSite().getPage().removeSelectionListener(this); - super.dispose(); - } - - @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { - if (!(part instanceof GLFunctionTraceViewer)) { - return; - } - - if (((GLFunctionTraceViewer) part).getTrace() != mTrace) { - return; - } - - if (!(selection instanceof TreeSelection)) { - return; - } - - GLCall selectedCall = null; - - Object data = ((TreeSelection) selection).getFirstElement(); - if (data instanceof GLCallNode) { - selectedCall = ((GLCallNode) data).getCall(); - } - - if (selectedCall == null) { - return; - } - - final int selectedCallIndex = selectedCall.getIndex(); - - // Creation of texture images takes a few seconds on the first run. So run - // the update task as an Eclipse job. - Job job = new Job("Updating GL State") { - @Override - protected IStatus run(IProgressMonitor monitor) { - Set<IGLProperty> changedProperties = null; - - try { - sGlStateLock.acquire(); - changedProperties = updateState(mCurrentStateIndex, - selectedCallIndex); - mCurrentStateIndex = selectedCallIndex; - } catch (Exception e) { - GlTracePlugin.getDefault().logMessage( - "Unexpected error while updating GL State."); - GlTracePlugin.getDefault().logMessage(e.getMessage()); - return new Status(Status.ERROR, - GlTracePlugin.PLUGIN_ID, - "Unexpected error while updating GL State.", - e); - } finally { - sGlStateLock.release(); - } - - mLabelProvider.setChangedProperties(changedProperties); - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - if (!mTreeViewer.getTree().isDisposed()) { - mTreeViewer.refresh(); - } - } - }); - - return Status.OK_STATUS; - } - }; - job.setPriority(Job.SHORT); - job.schedule(); - } - - @Override - public Control getControl() { - if (mTreeViewer == null) { - return null; - } - - return mTreeViewer.getControl(); - } - - @Override - public void setFocus() { - } - - /** - * Update GL state from GL call at fromIndex to the call at toIndex. - * If fromIndex < toIndex, the GL state will be updated by applying all the transformations - * corresponding to calls from (fromIndex + 1) to toIndex (inclusive). - * If fromIndex > toIndex, the GL state will be updated by reverting all the calls from - * fromIndex (inclusive) to (toIndex + 1). - * @return GL state properties that changed as a result of this update. - */ - private Set<IGLProperty> updateState(int fromIndex, int toIndex) { - assert fromIndex >= -1 && fromIndex < mGLCalls.size(); - assert toIndex >= 0 && toIndex < mGLCalls.size(); - - if (fromIndex < toIndex) { - return applyTransformations(fromIndex, toIndex); - } else if (fromIndex > toIndex) { - return revertTransformations(fromIndex, toIndex); - } else { - return Collections.emptySet(); - } - } - - private Set<IGLProperty> applyTransformations(int fromIndex, int toIndex) { - int setSizeHint = 3 * (toIndex - fromIndex) + 10; - Set<IGLProperty> changedProperties = new HashSet<IGLProperty>(setSizeHint); - - for (int i = fromIndex + 1; i <= toIndex; i++) { - GLCall call = mGLCalls.get(i); - for (IStateTransform f : call.getStateTransformations()) { - try { - f.apply(mState); - IGLProperty changedProperty = f.getChangedProperty(mState); - if (changedProperty != null) { - changedProperties.addAll(getHierarchy(changedProperty)); - } - } catch (Exception e) { - GlTracePlugin.getDefault().logMessage("Error applying transformations for " - + call); - GlTracePlugin.getDefault().logMessage(e.toString()); - } - } - } - - return changedProperties; - } - - private Set<IGLProperty> revertTransformations(int fromIndex, int toIndex) { - int setSizeHint = 3 * (fromIndex - toIndex) + 10; - Set<IGLProperty> changedProperties = new HashSet<IGLProperty>(setSizeHint); - - for (int i = fromIndex; i > toIndex; i--) { - List<IStateTransform> transforms = mGLCalls.get(i).getStateTransformations(); - // When reverting transformations, iterate from the last to first so that the reversals - // are performed in the correct sequence. - for (int j = transforms.size() - 1; j >= 0; j--) { - IStateTransform f = transforms.get(j); - f.revert(mState); - - IGLProperty changedProperty = f.getChangedProperty(mState); - if (changedProperty != null) { - changedProperties.addAll(getHierarchy(changedProperty)); - } - } - } - - return changedProperties; - } - - /** - * Obtain the list of properties starting from the provided property up to - * the root of GL state. - */ - private List<IGLProperty> getHierarchy(IGLProperty changedProperty) { - List<IGLProperty> changedProperties = new ArrayList<IGLProperty>(5); - changedProperties.add(changedProperty); - - // add the entire parent chain until we reach the root - IGLProperty prop = changedProperty; - while ((prop = prop.getParent()) != null) { - changedProperties.add(prop); - } - - return changedProperties; - } - - @Override - public void addSelectionChangedListener(ISelectionChangedListener listener) { - mTreeViewer.addSelectionChangedListener(listener); - } - - @Override - public ISelection getSelection() { - return mTreeViewer.getSelection(); - } - - @Override - public void removeSelectionChangedListener(ISelectionChangedListener listener) { - mTreeViewer.removeSelectionChangedListener(listener); - } - - @Override - public void setSelection(ISelection selection) { - mTreeViewer.setSelection(selection); - } -} |