diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views')
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(); + } +} |