aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FitToCanvasAction.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryView.java53
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java442
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/GLPageBookView.java83
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/SaveImageAction.java59
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/StateView.java57
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsPage.java232
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsView.java52
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/GlDrawCallDetailProvider.java82
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ICallDetailProvider.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IDetailProvider.java38
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IStateDetailProvider.java27
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderSourceDetailsProvider.java103
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderUniformDetailsProvider.java173
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/TextureImageDetailsProvider.java158
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VboDetailProvider.java189
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VertexAttribPointerDataDetailProvider.java72
17 files changed, 1891 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FitToCanvasAction.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FitToCanvasAction.java
new file mode 100644
index 000000000..1ee0fa0c2
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FitToCanvasAction.java
@@ -0,0 +1,40 @@
+/*
+ * 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.views;
+
+import com.android.ide.eclipse.gltrace.GlTracePlugin;
+import com.android.ide.eclipse.gltrace.widgets.ImageCanvas;
+
+import org.eclipse.jface.action.Action;
+
+public class FitToCanvasAction extends Action {
+ private ImageCanvas mImageCanvas;
+
+ public FitToCanvasAction(boolean fitByDefault, ImageCanvas canvas) {
+ super("Fit to Canvas", GlTracePlugin.getImageDescriptor("/icons/zoomfit.png")); //$NON-NLS-2$
+ setToolTipText("Fit Image to Canvas");
+ mImageCanvas = canvas;
+
+ setChecked(fitByDefault);
+ mImageCanvas.setFitToCanvas(fitByDefault);
+ }
+
+ @Override
+ public void run() {
+ mImageCanvas.setFitToCanvas(isChecked());
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryView.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryView.java
new file mode 100644
index 000000000..42eb98c8f
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryView.java
@@ -0,0 +1,53 @@
+/*
+ * 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.views;
+
+import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer;
+
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * The {@link FrameSummaryView} is a page book view with pages of type {@link FrameSummaryViewPage}.
+ */
+public class FrameSummaryView extends GLPageBookView {
+ public static final String ID = "com.android.ide.eclipse.gltrace.views.FrameBuffer"; //$NON-NLS-1$
+
+ public FrameSummaryView() {
+ super("Open a GL Trace file to view the framebuffer contents.");
+ }
+
+ @Override
+ protected PageRec doCreatePage(IWorkbenchPart part) {
+ if (!(part instanceof GLFunctionTraceViewer)) {
+ return null;
+ }
+
+ GLFunctionTraceViewer viewer = (GLFunctionTraceViewer) part;
+ FrameSummaryViewPage page = viewer.getFrameSummaryViewPage();
+ initPage(page);
+ page.createControl(getPageBook());
+
+ return new PageRec(part, page);
+ }
+
+ @Override
+ protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) {
+ FrameSummaryViewPage page = (FrameSummaryViewPage) pageRecord.page;
+ page.dispose();
+ pageRecord.dispose();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java
new file mode 100644
index 000000000..25de48f20
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java
@@ -0,0 +1,442 @@
+/*
+ * 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.views;
+
+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 com.android.ide.eclipse.gltrace.widgets.ImageCanvas;
+
+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.IToolBarManager;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.part.Page;
+
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A {@link FrameSummaryViewPage} displays summary information regarding a frame. This includes
+ * the contents of the frame buffer at the end of the frame, and statistics regarding the
+ * OpenGL Calls present in the frame.
+ */
+public class FrameSummaryViewPage extends Page {
+ private GLTrace mTrace;
+
+ private final Object mLock = new Object();
+ private Job mRefresherJob;
+ private int mCurrentFrame;
+
+ private SashForm mSash;
+ private ImageCanvas mImageCanvas;
+
+ private Label mWallClockTimeLabel;
+ private Label mThreadTimeLabel;
+
+ private TableViewer mStatsTableViewer;
+ private StatsLabelProvider mStatsLabelProvider;
+ private StatsTableComparator mStatsTableComparator;
+
+ private FitToCanvasAction mFitToCanvasAction;
+ private SaveImageAction mSaveImageAction;
+
+ private static final String[] STATS_TABLE_PROPERTIES = {
+ "Function",
+ "Count",
+ "Wall Time (ns)",
+ "Thread Time (ns)",
+ };
+ private static final float[] STATS_TABLE_COLWIDTH_RATIOS = {
+ 0.4f, 0.1f, 0.25f, 0.25f,
+ };
+ private static final int[] STATS_TABLE_COL_ALIGNMENT = {
+ SWT.LEFT, SWT.LEFT, SWT.RIGHT, SWT.RIGHT,
+ };
+
+ public FrameSummaryViewPage(GLTrace trace) {
+ mTrace = trace;
+ }
+
+ public void setInput(GLTrace trace) {
+ mTrace = trace;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mSash = new SashForm(parent, SWT.VERTICAL);
+
+ // create image canvas where the framebuffer is displayed
+ mImageCanvas = new ImageCanvas(mSash);
+
+ // create a composite where the frame statistics are displayed
+ createFrameStatisticsPart(mSash);
+
+ mSash.setWeights(new int[] {70, 30});
+
+ mFitToCanvasAction = new FitToCanvasAction(true, mImageCanvas);
+ mSaveImageAction = new SaveImageAction(mImageCanvas);
+
+ IToolBarManager toolbarManager = getSite().getActionBars().getToolBarManager();
+ toolbarManager.add(mFitToCanvasAction);
+ toolbarManager.add(mSaveImageAction);
+ }
+
+ private void createFrameStatisticsPart(Composite parent) {
+ Composite c = new Composite(parent, SWT.NONE);
+ c.setLayout(new GridLayout(2, false));
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(c);
+
+ Label l = new Label(c, SWT.NONE);
+ l.setText("Cumulative call duration of all OpenGL Calls in this frame:");
+ l.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY));
+ GridDataFactory.fillDefaults().span(2, 1).applyTo(l);
+
+ l = new Label(c, SWT.NONE);
+ l.setText("Wall Clock Time: ");
+ GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(l);
+
+ mWallClockTimeLabel = new Label(c, SWT.NONE);
+ GridDataFactory.defaultsFor(mWallClockTimeLabel)
+ .grab(true, false)
+ .applyTo(mWallClockTimeLabel);
+
+ l = new Label(c, SWT.NONE);
+ l.setText("Thread Time: ");
+ GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(l);
+
+ mThreadTimeLabel = new Label(c, SWT.NONE);
+ GridDataFactory.defaultsFor(mThreadTimeLabel)
+ .grab(true, false)
+ .applyTo(mThreadTimeLabel);
+
+ l = new Label(c, SWT.HORIZONTAL | SWT.SEPARATOR);
+ GridDataFactory.fillDefaults().span(2, 1).applyTo(l);
+
+ l = new Label(c, SWT.NONE);
+ l.setText("Per OpenGL Function Statistics:");
+ l.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY));
+ GridDataFactory.fillDefaults().span(2, 1).applyTo(l);
+
+ final Table table = new Table(c, SWT.BORDER | SWT.FULL_SELECTION);
+ GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(table);
+
+ table.setLinesVisible(true);
+ table.setHeaderVisible(true);
+
+ mStatsTableViewer = new TableViewer(table);
+ mStatsLabelProvider = new StatsLabelProvider();
+ mStatsTableComparator = new StatsTableComparator(1);
+
+ // when a column is selected, sort the table based on that column
+ SelectionListener columnSelectionListener = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ TableColumn tc = (TableColumn) e.widget;
+ String colText = tc.getText();
+ for (int i = 0; i < STATS_TABLE_PROPERTIES.length; i++) {
+ if (STATS_TABLE_PROPERTIES[i].equals(colText)) {
+ mStatsTableComparator.setSortColumn(i);
+ table.setSortColumn(tc);
+ table.setSortDirection(mStatsTableComparator.getDirection());
+ mStatsTableViewer.refresh();
+ break;
+ }
+ }
+ }
+ };
+
+ for (int i = 0; i < STATS_TABLE_PROPERTIES.length; i++) {
+ TableViewerColumn tvc = new TableViewerColumn(mStatsTableViewer, SWT.NONE);
+ tvc.getColumn().setText(STATS_TABLE_PROPERTIES[i]);
+ tvc.setLabelProvider(mStatsLabelProvider);
+ tvc.getColumn().setAlignment(STATS_TABLE_COL_ALIGNMENT[i]);
+ tvc.getColumn().addSelectionListener(columnSelectionListener);
+ }
+ mStatsTableViewer.setContentProvider(new StatsContentProvider());
+ mStatsTableViewer.setInput(null);
+ mStatsTableViewer.setComparator(mStatsTableComparator);
+
+ // resize columns appropriately when the size of the widget changes
+ table.addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent e) {
+ int w = table.getClientArea().width;
+
+ for (int i = 0; i < STATS_TABLE_COLWIDTH_RATIOS.length; i++) {
+ table.getColumn(i).setWidth((int) (w * STATS_TABLE_COLWIDTH_RATIOS[i]));
+ }
+ }
+ });
+ }
+
+ @Override
+ public Control getControl() {
+ return mSash;
+ }
+
+ @Override
+ public void setFocus() {
+ }
+
+ public void setSelectedFrame(int frame) {
+ if (mTrace == null) {
+ return;
+ }
+
+ synchronized (mLock) {
+ mCurrentFrame = frame;
+
+ if (mRefresherJob != null) {
+ return;
+ }
+
+ mRefresherJob = new Job("Update Frame Summary Task") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ final int currentFrame;
+ synchronized (mLock) {
+ currentFrame = mCurrentFrame;
+ mRefresherJob = null;
+ };
+
+ updateImageCanvas(currentFrame);
+ updateFrameStats(currentFrame);
+
+ return Status.OK_STATUS;
+ }
+ };
+ mRefresherJob.setPriority(Job.SHORT);
+ mRefresherJob.schedule(500);
+ };
+ }
+
+ private void updateFrameStats(int frame) {
+ final List<GLCall> calls = mTrace.getGLCallsForFrame(frame);
+
+ Job job = new Job("Update Frame Statistics") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ long wallClockDuration = 0;
+ long threadDuration = 0;
+
+ final Map<Function, PerCallStats> cumulativeStats =
+ new EnumMap<Function, PerCallStats>(Function.class);
+
+ for (GLCall c: calls) {
+ wallClockDuration += c.getWallDuration();
+ threadDuration += c.getThreadDuration();
+
+ PerCallStats stats = cumulativeStats.get(c.getFunction());
+ if (stats == null) {
+ stats = new PerCallStats();
+ }
+
+ stats.count++;
+ stats.threadDuration += c.getThreadDuration();
+ stats.wallDuration += c.getWallDuration();
+
+ cumulativeStats.put(c.getFunction(), stats);
+ }
+
+ final String wallTime = formatMilliSeconds(wallClockDuration);
+ final String threadTime = formatMilliSeconds(threadDuration);
+
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ mWallClockTimeLabel.setText(wallTime);
+ mThreadTimeLabel.setText(threadTime);
+ mStatsTableViewer.setInput(cumulativeStats);
+ }
+ });
+
+ return Status.OK_STATUS;
+ }
+ };
+ job.setUser(true);
+ job.schedule();
+ }
+
+ private String formatMilliSeconds(long nanoSeconds) {
+ double milliSeconds = (double) nanoSeconds / 1000000;
+ return String.format("%.2f ms", milliSeconds); //$NON-NLS-1$
+ }
+
+ private void updateImageCanvas(int frame) {
+ int lastCallIndex = mTrace.getFrame(frame).getEndIndex() - 1;
+ if (lastCallIndex >= 0 && lastCallIndex < mTrace.getGLCalls().size()) {
+ GLCall call = mTrace.getGLCalls().get(lastCallIndex);
+ final Image image = mTrace.getImage(call);
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ mImageCanvas.setImage(image);
+
+ mFitToCanvasAction.setEnabled(image != null);
+ mSaveImageAction.setEnabled(image != null);
+ }
+ });
+ }
+ }
+
+ /** Cumulative stats maintained for each type of OpenGL Function in a particular frame. */
+ private static class PerCallStats {
+ public int count;
+ public long wallDuration;
+ public long threadDuration;
+ }
+
+ private static class StatsContentProvider implements IStructuredContentProvider {
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof Map<?, ?>) {
+ return ((Map<?, ?>) inputElement).entrySet().toArray();
+ }
+
+ return null;
+ }
+ }
+
+ private static class StatsLabelProvider extends ColumnLabelProvider {
+ @Override
+ public void update(ViewerCell cell) {
+ Object element = cell.getElement();
+ if (!(element instanceof Map.Entry<?, ?>)) {
+ return;
+ }
+
+ Function f = (Function) ((Map.Entry<?, ?>) element).getKey();
+ PerCallStats stats = (PerCallStats) ((Map.Entry<?, ?>) element).getValue();
+
+ switch (cell.getColumnIndex()) {
+ case 0:
+ cell.setText(f.toString());
+ break;
+ case 1:
+ cell.setText(Integer.toString(stats.count));
+ break;
+ case 2:
+ cell.setText(formatDuration(stats.wallDuration));
+ break;
+ case 3:
+ cell.setText(formatDuration(stats.threadDuration));
+ break;
+ default:
+ // should not happen
+ cell.setText("??"); //$NON-NLS-1$
+ break;
+ }
+ }
+
+ private String formatDuration(long time) {
+ // Max duration is in the 10s of milliseconds = 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 StatsTableComparator extends ViewerComparator {
+ private int mSortColumn;
+ private boolean mDescending = true;
+
+ private StatsTableComparator(int defaultSortColIndex) {
+ mSortColumn = defaultSortColIndex;
+ }
+
+ public void setSortColumn(int index) {
+ if (index == mSortColumn) {
+ // if same column as what we are currently sorting on,
+ // then toggle the direction
+ mDescending = !mDescending;
+ } else {
+ mSortColumn = index;
+ mDescending = true;
+ }
+ }
+
+ public int getDirection() {
+ return mDescending ? SWT.UP : SWT.DOWN;
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ Map.Entry<?, ?> entry1;
+ Map.Entry<?, ?> entry2;
+
+ if (mDescending) {
+ entry1 = (Map.Entry<?, ?>) e1;
+ entry2 = (Map.Entry<?, ?>) e2;
+ } else {
+ entry1 = (Map.Entry<?, ?>) e2;
+ entry2 = (Map.Entry<?, ?>) e1;
+ }
+
+ String k1 = entry1.getKey().toString();
+ String k2 = entry2.getKey().toString();
+
+ PerCallStats stats1 = (PerCallStats) entry1.getValue();
+ PerCallStats stats2 = (PerCallStats) entry2.getValue();
+
+ switch (mSortColumn) {
+ case 0: // function name
+ return String.CASE_INSENSITIVE_ORDER.compare(k1, k2);
+ case 1:
+ return stats1.count - stats2.count;
+ case 2:
+ return (int) (stats1.wallDuration - stats2.wallDuration);
+ case 3:
+ return (int) (stats1.threadDuration - stats2.threadDuration);
+ default:
+ return super.compare(viewer, e1, e2);
+ }
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/GLPageBookView.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/GLPageBookView.java
new file mode 100644
index 000000000..12405539b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/GLPageBookView.java
@@ -0,0 +1,83 @@
+/*
+ * 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.views;
+
+import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer;
+
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.part.IPage;
+import org.eclipse.ui.part.IPageSite;
+import org.eclipse.ui.part.MessagePage;
+import org.eclipse.ui.part.PageBook;
+import org.eclipse.ui.part.PageBookView;
+
+/**
+ * {@link GLPageBookView} is an abstract {@link PageBookView} that can be used
+ * to provide page book view's whose main part is a {@link GLFunctionTraceViewer}.
+ */
+public abstract class GLPageBookView extends PageBookView {
+ private final String mDefaultMessage;
+
+ public GLPageBookView(String defaultMessage) {
+ super();
+
+ mDefaultMessage = defaultMessage;
+ }
+
+ @Override
+ protected IPage createDefaultPage(PageBook book) {
+ MessagePage page = new MessagePage();
+ initPage(page);
+ page.createControl(book);
+ page.setMessage(mDefaultMessage);
+ return page;
+ }
+
+ @Override
+ protected IWorkbenchPart getBootstrapPart() {
+ IWorkbenchPage page = getSite().getPage();
+ if (page != null) {
+ return page.getActiveEditor();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected boolean isImportant(IWorkbenchPart part) {
+ return part instanceof GLFunctionTraceViewer;
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPart part) {
+ partActivated(part);
+ }
+
+ @Override
+ protected void showPageRec(PageRec pageRec) {
+ IPageSite pageSite = getPageSite(pageRec.page);
+ if (pageRec.page instanceof ISelectionProvider) {
+ pageSite.setSelectionProvider((ISelectionProvider) pageRec.page);
+ } else {
+ pageSite.setSelectionProvider(null); // clear selection provider
+ }
+
+ super.showPageRec(pageRec);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/SaveImageAction.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/SaveImageAction.java
new file mode 100644
index 000000000..6cc8b699c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/SaveImageAction.java
@@ -0,0 +1,59 @@
+/*
+ * 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.views;
+
+import com.android.ide.eclipse.gltrace.widgets.ImageCanvas;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+import java.io.File;
+
+public class SaveImageAction extends Action {
+ private static String sLastUsedPath;
+
+ private ImageCanvas mImageCanvas;
+
+ public SaveImageAction(ImageCanvas canvas) {
+ super("Save Image",
+ PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(
+ ISharedImages.IMG_ETOOL_SAVEAS_EDIT));
+ setToolTipText("Save Image");
+ mImageCanvas = canvas;
+ }
+
+ @Override
+ public void run() {
+ FileDialog fd = new FileDialog(mImageCanvas.getShell(), SWT.SAVE);
+ fd.setFilterExtensions(new String[] { "*.png" });
+ if (sLastUsedPath != null) {
+ fd.setFilterPath(sLastUsedPath);
+ }
+
+ String path = fd.open();
+ if (path == null) {
+ return;
+ }
+
+ File f = new File(path);
+ sLastUsedPath = f.getParent();
+ mImageCanvas.exportImageTo(f);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/StateView.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/StateView.java
new file mode 100644
index 000000000..eff2fefaf
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/StateView.java
@@ -0,0 +1,57 @@
+/*
+ * 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.views;
+
+import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer;
+import com.android.ide.eclipse.gltrace.editors.StateViewPage;
+
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * The StateView shows the GL state for the current active {@link GLFunctionTraceViewer}.
+ * It behaves like the Eclipse Outline View: Each active editor provides the GL state content
+ * to show via a {@link StateViewPage}. This class simply acts as a stack view showing the
+ * state corresponding to whichever editor is active.
+ */
+public class StateView extends GLPageBookView {
+ public static final String ID = "com.android.ide.eclipse.gltrace.views.State"; //$NON-NLS-1$
+
+ public StateView() {
+ super("Open (or select) a GL Trace file to view the GL State.");
+ }
+
+ @Override
+ protected PageRec doCreatePage(IWorkbenchPart part) {
+ if (!(part instanceof GLFunctionTraceViewer)) {
+ return null;
+ }
+
+ GLFunctionTraceViewer viewer = (GLFunctionTraceViewer) part;
+ StateViewPage page = viewer.getStateViewPage();
+ initPage(page);
+ page.createControl(getPageBook());
+
+ return new PageRec(part, page);
+ }
+
+ @Override
+ protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) {
+ StateViewPage v = (StateViewPage) pageRecord.page;
+ v.dispose();
+ pageRecord.dispose();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsPage.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsPage.java
new file mode 100644
index 000000000..510898df9
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsPage.java
@@ -0,0 +1,232 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.editors.GLCallGroups.GLCallNode;
+import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer;
+import com.android.ide.eclipse.gltrace.model.GLCall;
+import com.android.ide.eclipse.gltrace.model.GLTrace;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+import com.android.ide.eclipse.gltrace.views.StateView;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.part.IPageSite;
+import org.eclipse.ui.part.Page;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class DetailsPage extends Page implements ISelectionListener {
+ private GLTrace mTrace;
+
+ private IToolBarManager mToolBarManager;
+ private Composite mTopComposite;
+ private StackLayout mStackLayout;
+ private Composite mBlankComposite;
+
+ private List<IDetailProvider> mDetailProviders = Arrays.asList(
+ new ShaderSourceDetailsProvider(),
+ new ShaderUniformDetailsProvider(),
+ new TextureImageDetailsProvider(),
+ new VboDetailProvider(),
+ new GlDrawCallDetailProvider(),
+ new VertexAttribPointerDataDetailProvider());
+
+ public DetailsPage(GLTrace trace) {
+ mTrace = trace;
+ }
+
+ public void setInput(GLTrace trace) {
+ mTrace = trace;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mTopComposite = new Composite(parent, SWT.NONE);
+ mStackLayout = new StackLayout();
+ mTopComposite.setLayout(mStackLayout);
+ mTopComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ mBlankComposite = new Composite(mTopComposite, SWT.NONE);
+
+ mToolBarManager = getSite().getActionBars().getToolBarManager();
+
+ for (IDetailProvider provider : mDetailProviders) {
+ provider.createControl(mTopComposite);
+
+ for (IContributionItem item: provider.getToolBarItems()) {
+ mToolBarManager.add(item);
+ }
+ }
+
+ setDetailsProvider(null);
+ }
+
+ private void setDetailsProvider(IDetailProvider provider) {
+ for (IContributionItem item: mToolBarManager.getItems()) {
+ item.setVisible(false);
+ }
+
+ if (provider == null) {
+ setTopControl(mBlankComposite);
+ } else {
+ setTopControl(provider.getControl());
+
+ for (IContributionItem item: provider.getToolBarItems()) {
+ item.setVisible(true);
+ }
+ }
+
+ mToolBarManager.update(true);
+ }
+
+ private void setTopControl(Control c) {
+ mStackLayout.topControl = c;
+ mTopComposite.layout();
+ }
+
+ @Override
+ public Control getControl() {
+ return mTopComposite;
+ }
+
+ @Override
+ public void init(IPageSite pageSite) {
+ super.init(pageSite);
+ pageSite.getPage().addSelectionListener(this);
+ }
+
+ @Override
+ public void dispose() {
+ getSite().getPage().removeSelectionListener(this);
+
+ for (IDetailProvider provider : mDetailProviders) {
+ provider.disposeControl();
+ }
+
+ super.dispose();
+ }
+
+ @Override
+ public void setFocus() {
+ }
+
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if (part instanceof GLFunctionTraceViewer) {
+ GLCall selectedCall = getSelectedCall((GLFunctionTraceViewer) part, selection);
+ if (selectedCall == null) {
+ return;
+ }
+
+ callSelected(selectedCall);
+ return;
+ } else if (part instanceof StateView) {
+ IGLProperty selectedProperty = getSelectedProperty((StateView) part, selection);
+ if (selectedProperty == null) {
+ return;
+ }
+
+ stateVariableSelected(selectedProperty);
+ return;
+ }
+
+ return;
+ }
+
+ private void stateVariableSelected(IGLProperty property) {
+ for (IDetailProvider p : mDetailProviders) {
+ if (!(p instanceof IStateDetailProvider)) {
+ continue;
+ }
+
+ IStateDetailProvider sp = (IStateDetailProvider) p;
+ if (sp.isApplicable(property)) {
+ sp.updateControl(property);
+ setDetailsProvider(sp);
+ return;
+ }
+ }
+
+ setDetailsProvider(null);
+ return;
+ }
+
+ private void callSelected(GLCall selectedCall) {
+ for (IDetailProvider p : mDetailProviders) {
+ if (!(p instanceof ICallDetailProvider)) {
+ continue;
+ }
+
+ ICallDetailProvider cp = (ICallDetailProvider) p;
+ if (cp.isApplicable(selectedCall)) {
+ cp.updateControl(mTrace, selectedCall);
+ setDetailsProvider(cp);
+ return;
+ }
+ }
+
+ setDetailsProvider(null);
+ return;
+ }
+
+ private GLCall getSelectedCall(GLFunctionTraceViewer part, ISelection selection) {
+ if (part.getTrace() != mTrace) {
+ return null;
+ }
+
+ if (!(selection instanceof TreeSelection)) {
+ return null;
+ }
+
+ Object data = ((TreeSelection) selection).getFirstElement();
+ if (data instanceof GLCallNode) {
+ return ((GLCallNode) data).getCall();
+ } else {
+ return null;
+ }
+ }
+
+ private IGLProperty getSelectedProperty(StateView view, ISelection selection) {
+ if (!(selection instanceof IStructuredSelection)) {
+ return null;
+ }
+
+ IStructuredSelection ssel = (IStructuredSelection) selection;
+ @SuppressWarnings("rawtypes")
+ List objects = ssel.toList();
+ if (objects.size() > 0) {
+ Object data = objects.get(0);
+ if (data instanceof IGLProperty) {
+ return (IGLProperty) data;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsView.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsView.java
new file mode 100644
index 000000000..0a2d88e52
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsView.java
@@ -0,0 +1,52 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer;
+import com.android.ide.eclipse.gltrace.views.GLPageBookView;
+
+import org.eclipse.ui.IWorkbenchPart;
+
+public class DetailsView extends GLPageBookView {
+ public static final String ID = "com.android.ide.eclipse.gltrace.views.Details"; //$NON-NLS-1$
+
+ public DetailsView() {
+ super(""); //$NON-NLS-1$
+ }
+
+ @Override
+ protected PageRec doCreatePage(IWorkbenchPart part) {
+ if (!(part instanceof GLFunctionTraceViewer)) {
+ return null;
+ }
+
+ GLFunctionTraceViewer viewer = (GLFunctionTraceViewer) part;
+ DetailsPage page = viewer.getDetailsPage();
+
+ initPage(page);
+ page.createControl(getPageBook());
+
+ return new PageRec(part, page);
+ }
+
+ @Override
+ protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) {
+ DetailsPage page = (DetailsPage) pageRecord.page;
+ page.dispose();
+ pageRecord.dispose();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/GlDrawCallDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/GlDrawCallDetailProvider.java
new file mode 100644
index 000000000..44a05ffc9
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/GlDrawCallDetailProvider.java
@@ -0,0 +1,82 @@
+/*
+ * 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.views.detail;
+
+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 com.android.ide.eclipse.gltrace.views.FitToCanvasAction;
+import com.android.ide.eclipse.gltrace.views.SaveImageAction;
+import com.android.ide.eclipse.gltrace.widgets.ImageCanvas;
+
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class GlDrawCallDetailProvider implements ICallDetailProvider {
+ private ImageCanvas mImageCanvas;
+ private FitToCanvasAction mFitToCanvasAction;
+ private SaveImageAction mSaveImageAction;
+ private List<IContributionItem> mToolBarItems;
+
+ @Override
+ public boolean isApplicable(GLCall call) {
+ return (call.getFunction() == Function.glDrawArrays
+ || call.getFunction() == Function.glDrawElements) && call.hasFb();
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mImageCanvas = new ImageCanvas(parent);
+ mImageCanvas.setFitToCanvas(false);
+
+ mFitToCanvasAction = new FitToCanvasAction(false, mImageCanvas);
+ mSaveImageAction = new SaveImageAction(mImageCanvas);
+
+ mToolBarItems = Arrays.asList(
+ (IContributionItem) new ActionContributionItem(mFitToCanvasAction),
+ (IContributionItem) new ActionContributionItem(mSaveImageAction));
+ }
+
+ @Override
+ public void disposeControl() {
+ if (mImageCanvas != null) {
+ mImageCanvas.dispose();
+ mImageCanvas = null;
+ }
+ }
+
+ @Override
+ public Control getControl() {
+ return mImageCanvas;
+ }
+
+ @Override
+ public void updateControl(GLTrace trace, GLCall call) {
+ mImageCanvas.setImage(trace.getImage(call));
+ mImageCanvas.setFitToCanvas(true);
+ }
+
+ @Override
+ public List<IContributionItem> getToolBarItems() {
+ return mToolBarItems;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ICallDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ICallDetailProvider.java
new file mode 100644
index 000000000..51770f35b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ICallDetailProvider.java
@@ -0,0 +1,31 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.model.GLCall;
+import com.android.ide.eclipse.gltrace.model.GLTrace;
+
+public interface ICallDetailProvider extends IDetailProvider {
+ /** Is this provider applicable for given {@link GLCall}? */
+ boolean isApplicable(GLCall call);
+
+ /**
+ * Update the detail view for given {@link GLCall} that is part of the given
+ * {@link GLTrace}.
+ */
+ void updateControl(GLTrace trace, GLCall call);
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IDetailProvider.java
new file mode 100644
index 000000000..1fc5174d3
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IDetailProvider.java
@@ -0,0 +1,38 @@
+/*
+ * 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.views.detail;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+import java.util.List;
+
+public interface IDetailProvider {
+ /** Create the controls to display the details. */
+ void createControl(Composite parent);
+
+ /** Dispose off any created controls. */
+ void disposeControl();
+
+ /** Obtain the top level control used by this detail provider. */
+ Control getControl();
+
+
+ /** Obtain a list of tool bar items to be displayed when this provider is active. */
+ List<IContributionItem> getToolBarItems();
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IStateDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IStateDetailProvider.java
new file mode 100644
index 000000000..4ad06beba
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IStateDetailProvider.java
@@ -0,0 +1,27 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+public interface IStateDetailProvider extends IDetailProvider {
+ /** Is this provider applicable for given GL state property? */
+ boolean isApplicable(IGLProperty state);
+
+ /** Update the detail view for given GL state property. */
+ void updateControl(IGLProperty state);
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderSourceDetailsProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderSourceDetailsProvider.java
new file mode 100644
index 000000000..ca986c355
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderSourceDetailsProvider.java
@@ -0,0 +1,103 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.state.GLCompositeProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.GLStringProperty;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ShaderSourceDetailsProvider implements IStateDetailProvider {
+ private Text mTextControl;
+
+ @Override
+ public boolean isApplicable(IGLProperty state) {
+ return getShaderSourceProperty(state) != null;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mTextControl = new Text(parent, SWT.BORDER| SWT.READ_ONLY
+ | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
+ mTextControl.setEditable(false);
+ }
+
+ @Override
+ public void disposeControl() {
+ }
+
+ @Override
+ public Control getControl() {
+ return mTextControl;
+ }
+
+ @Override
+ public void updateControl(IGLProperty state) {
+ IGLProperty shaderSrcProperty = getShaderSourceProperty(state);
+ if (shaderSrcProperty instanceof GLStringProperty) {
+ String shaderSrc = ((GLStringProperty) shaderSrcProperty).getStringValue();
+ mTextControl.setText(shaderSrc);
+ mTextControl.setEnabled(true);
+ } else {
+ mTextControl.setText(""); //$NON-NLS-1$
+ mTextControl.setEnabled(false);
+ }
+ }
+
+ /**
+ * Get the {@link GLStateType#SHADER_SOURCE} property given a node in
+ * the state hierarchy.
+ * @param state any node in the GL state hierarchy
+ * @return The {@link GLStateType#SHADER_SOURCE} property if a unique instance
+ * of it can be accessed from the given node, null otherwise.
+ * A unique instance can be accessed if the given node is
+ * either the requested node itself, or its parent or sibling.
+ */
+ private IGLProperty getShaderSourceProperty(IGLProperty state) {
+ if (state.getType() == GLStateType.SHADER_SOURCE) {
+ // given node is the requested node
+ return state;
+ }
+
+ if (state.getType() != GLStateType.PER_SHADER_STATE) {
+ // if it is not the parent, then it could be a sibling, in which case
+ // we go up a level to its parent
+ state = state.getParent();
+ }
+
+ if (state != null && state.getType() == GLStateType.PER_SHADER_STATE) {
+ // if it is the parent, we can access the required property
+ return ((GLCompositeProperty) state).getProperty(GLStateType.SHADER_SOURCE);
+ }
+
+ return null;
+ }
+
+ @Override
+ public List<IContributionItem> getToolBarItems() {
+ return Collections.emptyList();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderUniformDetailsProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderUniformDetailsProvider.java
new file mode 100644
index 000000000..2e3f7254b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderUniformDetailsProvider.java
@@ -0,0 +1,173 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.GLEnum;
+import com.android.ide.eclipse.gltrace.state.GLCompositeProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+import com.google.common.base.Joiner;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ShaderUniformDetailsProvider implements IStateDetailProvider {
+ private Text mTextControl;
+ private static final Joiner JOINER = Joiner.on(", ");
+
+ @Override
+ public boolean isApplicable(IGLProperty state) {
+ return getShaderUniformProperty(state) != null;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mTextControl = new Text(parent, SWT.BORDER | SWT.READ_ONLY | SWT.MULTI | SWT.WRAP);
+ mTextControl.setEditable(false);
+ }
+
+ @Override
+ public void disposeControl() {
+ }
+
+ @Override
+ public Control getControl() {
+ return mTextControl;
+ }
+
+ @Override
+ public void updateControl(IGLProperty state) {
+ IGLProperty uniform = getShaderUniformProperty(state);
+ if (uniform instanceof GLCompositeProperty) {
+ GLCompositeProperty uniformProperty = (GLCompositeProperty) uniform;
+ IGLProperty nameProperty = uniformProperty.getProperty(GLStateType.UNIFORM_NAME);
+ IGLProperty typeProperty = uniformProperty.getProperty(GLStateType.UNIFORM_TYPE);
+ IGLProperty valueProperty = uniformProperty.getProperty(GLStateType.UNIFORM_VALUE);
+
+ String name = (String) nameProperty.getValue();
+ GLEnum type = (GLEnum) typeProperty.getValue();
+ Object value = valueProperty.getValue();
+ mTextControl.setText(formatUniform(name, type, value));
+ mTextControl.setEnabled(true);
+ } else {
+ mTextControl.setText(""); //$NON-NLS-1$
+ mTextControl.setEnabled(false);
+ }
+ }
+
+ private String formatUniform(String name, GLEnum type, Object value) {
+ String valueText;
+
+ switch (type) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ valueText = formatVector(value);
+ break;
+ case GL_FLOAT_MAT2:
+ valueText = formatMatrix(2, value);
+ break;
+ case GL_FLOAT_MAT3:
+ valueText = formatMatrix(3, value);
+ break;
+ case GL_FLOAT_MAT4:
+ valueText = formatMatrix(4, value);
+ break;
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ default:
+ valueText = value.toString();
+ break;
+ }
+
+ return String.format("%s %s = %s", type, name, valueText); //$NON-NLS-1$
+ }
+
+ private String formatVector(Object value) {
+ if (value instanceof List<?>) {
+ List<?> list = (List<?>) value;
+ StringBuilder sb = new StringBuilder(list.size() * 4);
+ sb.append('[');
+ JOINER.appendTo(sb, list);
+ sb.append(']');
+ return sb.toString();
+ }
+
+ return value.toString();
+ }
+
+ private String formatMatrix(int dimension, Object value) {
+ if (value instanceof List<?>) {
+ List<?> list = (List<?>) value;
+ if (list.size() != dimension * dimension) {
+ // Uniforms can only be square matrices, so this scenario should
+ // not occur.
+ return formatVector(value);
+ }
+
+ StringBuilder sb = new StringBuilder(list.size() * 4);
+ sb.append('[');
+ sb.append('\n');
+ for (int i = 0; i < dimension; i++) {
+ sb.append(" "); //$NON-NLS-1$
+ JOINER.appendTo(sb, list.subList(i * dimension, (i + 1) * dimension));
+ sb.append('\n');
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ return value.toString();
+ }
+
+ /**
+ * Get the {@link GLStateType#PER_UNIFORM_STATE} property given a node in
+ * the state hierarchy.
+ */
+ private IGLProperty getShaderUniformProperty(IGLProperty state) {
+ if (state.getType() == GLStateType.PER_UNIFORM_STATE) {
+ return state;
+ }
+
+ state = state.getParent();
+ if (state != null && state.getType() == GLStateType.PER_UNIFORM_STATE) {
+ return state;
+ }
+
+ return null;
+ }
+
+ @Override
+ public List<IContributionItem> getToolBarItems() {
+ return Collections.emptyList();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/TextureImageDetailsProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/TextureImageDetailsProvider.java
new file mode 100644
index 000000000..4dcbb10c4
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/TextureImageDetailsProvider.java
@@ -0,0 +1,158 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.state.GLCompositeProperty;
+import com.android.ide.eclipse.gltrace.state.GLSparseArrayProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.GLStringProperty;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+import com.android.ide.eclipse.gltrace.views.FitToCanvasAction;
+import com.android.ide.eclipse.gltrace.views.SaveImageAction;
+import com.android.ide.eclipse.gltrace.widgets.ImageCanvas;
+
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class TextureImageDetailsProvider implements IStateDetailProvider {
+ private ImageCanvas mImageCanvas;
+ private FitToCanvasAction mFitToCanvasAction;
+ private SaveImageAction mSaveImageAction;
+ private List<IContributionItem> mToolBarItems;
+
+ @Override
+ public boolean isApplicable(IGLProperty state) {
+ return getTextureImageProperty(state) != null;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mImageCanvas = new ImageCanvas(parent);
+ mImageCanvas.setFitToCanvas(false);
+
+ mFitToCanvasAction = new FitToCanvasAction(false, mImageCanvas);
+ mSaveImageAction = new SaveImageAction(mImageCanvas);
+
+ mToolBarItems = Arrays.asList(
+ (IContributionItem) new ActionContributionItem(mFitToCanvasAction),
+ (IContributionItem) new ActionContributionItem(mSaveImageAction));
+ }
+
+ @Override
+ public void disposeControl() {
+ mImageCanvas.dispose();
+ mImageCanvas = null;
+ }
+
+ @Override
+ public Control getControl() {
+ return mImageCanvas;
+ }
+
+ @Override
+ public void updateControl(IGLProperty state) {
+ IGLProperty imageProperty = getTextureImageProperty(state);
+ if (imageProperty == null) {
+ return;
+ }
+
+ String texturePath = ((GLStringProperty) imageProperty).getStringValue();
+ if (texturePath != null) {
+ mImageCanvas.setImage(new Image(Display.getDefault(), texturePath));
+ mImageCanvas.setFitToCanvas(false);
+ return;
+ }
+ }
+
+ /**
+ * Get the {@link GLStateType#TEXTURE_IMAGE} property given a node in
+ * the state hierarchy.
+ * @param state any node in the GL state hierarchy
+ * @return The {@link GLStateType#TEXTURE_IMAGE} property if a unique instance
+ * of it can be accessed from the given node. A unique instance can be
+ * accessed if the given node is either the requested node itself, or
+ * its parent or sibling. In cases where a unique instance cannot be
+ * accessed, but one of the texture mipmap levels can be accessed, then
+ * return the first texture mipmap level. This happens if the selected
+ * state is a child of {@link GLStateType#PER_TEXTURE_STATE}. Returns
+ * null otherwise.
+ */
+ private IGLProperty getTextureImageProperty(IGLProperty state) {
+ if (state.getType() == GLStateType.TEXTURE_IMAGE) {
+ // given node is the requested node
+ return state;
+ }
+
+ IGLProperty img = getImageFromPerTextureLevelState(state);
+ if (img != null) {
+ return img;
+ }
+
+ return getFirstMipmapImage(state);
+ }
+
+ /**
+ * Returns the {@link GLStateType#TEXTURE_IMAGE} if the provided state is either
+ * {@link GLStateType#PER_TEXTURE_LEVEL_STATE} or one of its children. Returns null otherwise.
+ */
+ private IGLProperty getImageFromPerTextureLevelState(IGLProperty state) {
+ if (state != null && state.getType() != GLStateType.PER_TEXTURE_LEVEL_STATE) {
+ state = state.getParent();
+ }
+
+ if (state == null || state.getType() != GLStateType.PER_TEXTURE_LEVEL_STATE) {
+ return null;
+ }
+
+ return ((GLCompositeProperty) state).getProperty(GLStateType.TEXTURE_IMAGE);
+ }
+
+ /**
+ * Returns the first mipmap level's image entry if the provided state is either
+ * {@link GLStateType#PER_TEXTURE_STATE} or one of its immediate children, null otherwise.
+ */
+ private IGLProperty getFirstMipmapImage(IGLProperty state) {
+ if (state != null && state.getType() != GLStateType.PER_TEXTURE_STATE) {
+ state = state.getParent();
+ }
+
+ if (state == null || state.getType() != GLStateType.PER_TEXTURE_STATE) {
+ return null;
+ }
+
+ IGLProperty mipmaps =
+ ((GLCompositeProperty) state).getProperty(GLStateType.TEXTURE_MIPMAPS);
+ if (!(mipmaps instanceof GLSparseArrayProperty)) {
+ return null;
+ }
+
+ IGLProperty perTextureLevelState = ((GLSparseArrayProperty) mipmaps).getProperty(0);
+ return getImageFromPerTextureLevelState(perTextureLevelState);
+ }
+
+ @Override
+ public List<IContributionItem> getToolBarItems() {
+ return mToolBarItems;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VboDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VboDetailProvider.java
new file mode 100644
index 000000000..e0ba947c5
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VboDetailProvider.java
@@ -0,0 +1,189 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.GLEnum;
+import com.android.ide.eclipse.gltrace.GLUtils;
+import com.android.ide.eclipse.gltrace.state.GLCompositeProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class VboDetailProvider implements IStateDetailProvider {
+ private static enum DisplayFormat {
+ GL_FLOAT,
+ GL_BYTE,
+ GL_UNSIGNED_BYTE,
+ GL_SHORT,
+ GL_UNSIGNED_SHORT,
+ GL_FIXED,
+ }
+
+ private Composite mComposite;
+
+ private Label mSizeLabel;
+ private Label mUsageLabel;
+ private Label mTypeLabel;
+ private Combo mDisplayFormatCombo;
+ private Text mTextControl;
+
+ private byte[] mBufferData;
+
+ @Override
+ public boolean isApplicable(IGLProperty state) {
+ return getVboProperty(state) != null;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mComposite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(2, false);
+ layout.marginWidth = layout.marginHeight = 0;
+ mComposite.setLayout(layout);
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(mComposite);
+
+ Label l = new Label(mComposite, SWT.NONE);
+ l.setText("Size: ");
+ GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(l);
+
+ mSizeLabel = new Label(mComposite, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(mSizeLabel);
+
+ l = new Label(mComposite, SWT.NONE);
+ l.setText("Usage: ");
+ GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(l);
+
+ mUsageLabel = new Label(mComposite, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(mUsageLabel);
+
+ l = new Label(mComposite, SWT.NONE);
+ l.setText("Type: ");
+ GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(l);
+
+ mTypeLabel = new Label(mComposite, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(mTypeLabel);
+
+ l = new Label(mComposite, SWT.NONE);
+ l.setText("Format Data As: ");
+ GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(l);
+
+ DisplayFormat[] values = DisplayFormat.values();
+ List<String> formats = new ArrayList<String>(values.length);
+ for (DisplayFormat format: values) {
+ formats.add(format.name());
+ }
+
+ mDisplayFormatCombo = new Combo(mComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
+ mDisplayFormatCombo.setItems(formats.toArray(new String[formats.size()]));
+ mDisplayFormatCombo.select(0);
+ mDisplayFormatCombo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ updateContents();
+ }
+ });
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(mDisplayFormatCombo);
+
+ mTextControl = new Text(mComposite, SWT.BORDER | SWT.READ_ONLY | SWT.MULTI
+ | SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
+ GridDataFactory.fillDefaults().span(2, 1).grab(true, true).applyTo(mTextControl);
+ mTextControl.setEditable(false);
+ }
+
+ @Override
+ public void disposeControl() {
+ }
+
+ @Override
+ public Control getControl() {
+ return mComposite;
+ }
+
+ @Override
+ public void updateControl(IGLProperty state) {
+ IGLProperty vbo = getVboProperty(state);
+ if (vbo instanceof GLCompositeProperty) {
+ GLCompositeProperty vboProperty = (GLCompositeProperty) vbo;
+
+ IGLProperty sizeProperty = vboProperty.getProperty(GLStateType.BUFFER_SIZE);
+ mSizeLabel.setText(sizeProperty.getStringValue() + " bytes"); //$NON-NLS-1$
+
+ IGLProperty usageProperty = vboProperty.getProperty(GLStateType.BUFFER_USAGE);
+ mUsageLabel.setText(usageProperty.getStringValue());
+
+ IGLProperty typeProperty = vboProperty.getProperty(GLStateType.BUFFER_TYPE);
+ mTypeLabel.setText(typeProperty.getStringValue());
+
+ IGLProperty dataProperty = vboProperty.getProperty(GLStateType.BUFFER_DATA);
+ mBufferData = (byte[]) dataProperty.getValue();
+ } else {
+ mBufferData = null;
+ }
+
+ updateContents();
+ }
+
+ private void updateContents() {
+ if (mBufferData != null) {
+ mTextControl.setText(GLUtils.formatData(mBufferData,
+ GLEnum.valueOf(mDisplayFormatCombo.getText())));
+ mTextControl.setEnabled(true);
+ mDisplayFormatCombo.setEnabled(true);
+ } else {
+ mTextControl.setText("");
+ mTextControl.setEnabled(false);
+ mDisplayFormatCombo.setEnabled(false);
+ }
+ }
+
+ @Override
+ public List<IContributionItem> getToolBarItems() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Get the {@link GLStateType#VBO_COMPOSITE} property given a node in
+ * the state hierarchy.
+ */
+ private IGLProperty getVboProperty(IGLProperty state) {
+ if (state.getType() == GLStateType.VBO_COMPOSITE) {
+ return state;
+ }
+
+ state = state.getParent();
+ if (state != null && state.getType() == GLStateType.VBO_COMPOSITE) {
+ return state;
+ }
+
+ return null;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VertexAttribPointerDataDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VertexAttribPointerDataDetailProvider.java
new file mode 100644
index 000000000..55f8d841c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VertexAttribPointerDataDetailProvider.java
@@ -0,0 +1,72 @@
+/*
+ * 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.views.detail;
+
+import com.android.ide.eclipse.gltrace.GLEnum;
+import com.android.ide.eclipse.gltrace.GLUtils;
+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 com.google.protobuf.ByteString;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+import java.util.Collections;
+import java.util.List;
+
+public class VertexAttribPointerDataDetailProvider implements ICallDetailProvider {
+ private Text mText;
+
+ @Override
+ public boolean isApplicable(GLCall call) {
+ return call.getFunction() == Function.glVertexAttribPointerData;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mText = new Text(parent, SWT.BORDER | SWT.READ_ONLY | SWT.MULTI
+ | SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
+ }
+
+ @Override
+ public void disposeControl() {
+ }
+
+ @Override
+ public Control getControl() {
+ return mText;
+ }
+
+ @Override
+ public void updateControl(GLTrace trace, GLCall call) {
+ // void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type, GLboolean norm,
+ // GLsizei stride, const GLvoid* ptr, int minIndex, int maxIndex)
+ GLEnum type = (GLEnum) call.getProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_TYPE);
+ byte[] data = (byte[]) call.getProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_DATA);
+
+ mText.setText(GLUtils.formatData(data, type));
+ }
+
+ @Override
+ public List<IContributionItem> getToolBarItems() {
+ return Collections.emptyList();
+ }
+}