diff options
8 files changed, 445 insertions, 178 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java index 33b9fd1..7b1b959 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java @@ -33,9 +33,12 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.net.Socket; public class CollectTraceAction implements IWorkbenchWindowActionDelegate { public void run(IAction action) { @@ -60,13 +63,10 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { return; } - String activityName = dlg.getApplicationToTrace(); - String traceDestination = dlg.getTraceDestination(); - String deviceName = dlg.getDevice(); + TraceOptions traceOptions = dlg.getTraceOptions(); - IDevice device = getDevice(deviceName); - - String appName = activityName.split("/")[0]; + IDevice device = getDevice(traceOptions.device); + String appName = traceOptions.activityToTrace.split("/")[0]; //$NON-NLS-1$ killApp(device, appName); try { @@ -84,7 +84,7 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { } try { - startActivity(device, activityName); + startActivity(device, traceOptions.activityToTrace); } catch (Exception e) { MessageDialog.openError(shell, "Setup GL Trace", "Error while launching application: " + e.getMessage()); @@ -99,19 +99,67 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { // if everything went well, the app should now be waiting for the gl debugger // to connect - startTracing(shell, traceDestination, port); + startTracing(shell, traceOptions, port); } - private void startTracing(Shell shell, String traceDestination, int port) { + private void startTracing(Shell shell, TraceOptions traceOptions, int port) { FileOutputStream fos = null; try { - fos = new FileOutputStream(traceDestination, false); + fos = new FileOutputStream(traceOptions.traceDestination, false); } catch (FileNotFoundException e) { // input path is valid, so this cannot occur } - GLTraceWriter writer = new GLTraceWriter(fos, port, new GLTraceCollectorDialog(shell)); - writer.start(); + Socket socket = new Socket(); + DataInputStream traceDataStream = null; + DataOutputStream traceCommandsStream = null; + try { + socket.connect(new java.net.InetSocketAddress("127.0.0.1", port)); //$NON-NLS-1$ + socket.setTcpNoDelay(true); + traceDataStream = new DataInputStream(socket.getInputStream()); + traceCommandsStream = new DataOutputStream(socket.getOutputStream()); + } catch (IOException e) { + MessageDialog.openError(shell, + "OpenGL Trace", + "Unable to connect to remote GL Trace Server: " + e.getMessage()); + return; + } + + // create channel to send trace commands to device + TraceCommandWriter traceCommandWriter = new TraceCommandWriter(traceCommandsStream); + try { + traceCommandWriter.setTraceOptions(traceOptions.collectFbOnEglSwap, + traceOptions.collectFbOnGlDraw, + traceOptions.collectTextureData); + } catch (IOException e) { + MessageDialog.openError(shell, + "OpenGL Trace", + "Unexpected error while setting trace options: " + e.getMessage()); + closeSocket(socket); + return; + } + + // create trace writer that writes to a trace file + TraceFileWriter traceFileWriter = new TraceFileWriter(fos, traceDataStream); + traceFileWriter.start(); + + GLTraceCollectorDialog dlg = new GLTraceCollectorDialog(shell, + traceFileWriter, + traceCommandWriter, + traceOptions); + dlg.open(); + + traceFileWriter.stopTracing(); + traceCommandWriter.close(); + closeSocket(socket); + } + + private void closeSocket(Socket socket) { + try { + socket.close(); + } catch (IOException e) { + // ignore error while closing socket + } } private void startActivity(IDevice device, String appName) @@ -120,7 +168,6 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { String startAppCmd = String.format( "am start %s -a android.intent.action.MAIN -c android.intent.category.LAUNCHER", //$NON-NLS-1$ appName); - System.out.println(startAppCmd); device.executeShellCommand(startAppCmd, new IgnoreOutputReceiver()); } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceCollectorDialog.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceCollectorDialog.java index 04944c2..e7897ec 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceCollectorDialog.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceCollectorDialog.java @@ -16,29 +16,45 @@ package com.android.ide.eclipse.gltrace; -import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.TitleAreaDialog; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.ProgressBar; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; + +import java.io.IOException; /** Dialog displayed while the trace is being streamed from device to host. */ -public class GLTraceCollectorDialog extends Dialog { - private Text mFramesCollectedText; - private Text mTraceFileSizeText; - private GLTraceWriter mWriter; - private int mFramesCollected; - private int mTraceFileSize; - - protected GLTraceCollectorDialog(Shell parentShell) { +public class GLTraceCollectorDialog extends TitleAreaDialog { + private static final String TITLE = "OpenGL ES Trace"; + private static final String DEFAULT_MESSAGE = "Trace collection in progress."; + + private TraceOptions mTraceOptions; + private final TraceFileWriter mTraceFileWriter; + private final TraceCommandWriter mTraceCommandWriter; + + private Label mFramesCollectedLabel; + private Label mTraceFileSizeLabel; + private StatusRefreshTask mRefreshTask; + + protected GLTraceCollectorDialog(Shell parentShell, TraceFileWriter traceFileWriter, + TraceCommandWriter traceCommandWriter, TraceOptions traceOptions) { super(parentShell); + mTraceFileWriter = traceFileWriter; + mTraceCommandWriter = traceCommandWriter; + mTraceOptions = traceOptions; } @Override @@ -55,84 +71,154 @@ public class GLTraceCollectorDialog extends Dialog { @Override protected Control createDialogArea(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(2, false)); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); + parent.setLayout(new GridLayout()); + + setTitle(TITLE); + setMessage(DEFAULT_MESSAGE); + + Group controlGroup = new Group(parent, SWT.BORDER); + controlGroup.setLayout(new GridLayout(2, false)); + controlGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + controlGroup.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE)); + controlGroup.setText("Trace Options"); + + createLabel(controlGroup, "Collect Framebuffer contents on eglSwapBuffers()"); + final Button eglSwapCheckBox = createButton(controlGroup, + mTraceOptions.collectFbOnEglSwap); + + createLabel(controlGroup, "Collect Framebuffer contents on glDraw*()"); + final Button glDrawCheckBox = createButton(controlGroup, mTraceOptions.collectFbOnGlDraw); + + createLabel(controlGroup, "Collect texture data for glTexImage*()"); + final Button glTexImageCheckBox = createButton(controlGroup, + mTraceOptions.collectTextureData); + + SelectionListener l = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + boolean eglSwap = eglSwapCheckBox.getSelection(); + boolean glDraw = glDrawCheckBox.getSelection(); + boolean glTexImage = glTexImageCheckBox.getSelection(); + + try { + mTraceCommandWriter.setTraceOptions(eglSwap, glDraw, glTexImage); + } catch (IOException e) { + eglSwapCheckBox.setEnabled(false); + glDrawCheckBox.setEnabled(false); + glTexImageCheckBox.setEnabled(false); + + MessageDialog.openError(Display.getDefault().getActiveShell(), + "OpenGL ES Trace", + "Error while setting trace options: " + e.getMessage()); + } - createLabel(c, "Frames Collected:"); - mFramesCollectedText = createText(c); + // update the text on the button + if (!(event.getSource() instanceof Button)) { + return; + } + Button sourceButton = (Button) event.getSource(); + sourceButton.setText(getToggleActionText(sourceButton.getSelection())); + sourceButton.pack(); + } + }; + + eglSwapCheckBox.addSelectionListener(l); + glDrawCheckBox.addSelectionListener(l); + glTexImageCheckBox.addSelectionListener(l); + + Group statusGroup = new Group(parent, SWT.NONE); + statusGroup.setLayout(new GridLayout(2, false)); + statusGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + statusGroup.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE)); + statusGroup.setText("Trace Status"); - createLabel(c, "Trace File Size:"); - mTraceFileSizeText = createText(c); + createLabel(statusGroup, "Frames Collected:"); + mFramesCollectedLabel = createLabel(statusGroup, ""); - ProgressBar pb = new ProgressBar(c, SWT.INDETERMINATE); + createLabel(statusGroup, "Trace File Size:"); + mTraceFileSizeLabel = createLabel(statusGroup, ""); + + ProgressBar pb = new ProgressBar(statusGroup, SWT.INDETERMINATE); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; pb.setLayoutData(gd); + mRefreshTask = new StatusRefreshTask(); + new Thread(mRefreshTask, "Trace Status Refresh Thread").start(); + return super.createDialogArea(parent); } - private Text createText(Composite c) { - Text t = new Text(c, SWT.BORDER); - - GridData gd = new GridData(); - gd.widthHint = 100; - t.setLayoutData(gd); + private Button createButton(Composite controlComposite, boolean selection) { + Button b = new Button(controlComposite, SWT.TOGGLE); + b.setText(getToggleActionText(selection)); + b.setSelection(selection); + return b; + } - return t; + /** Get text to show on toggle box given its current selection. */ + private String getToggleActionText(boolean en) { + return en ? "Disable" : "Enable"; } - private void createLabel(Composite parent, String text) { + private Label createLabel(Composite parent, String text) { Label l = new Label(parent, SWT.NONE); l.setText(text); - GridData gd = new GridData(); - gd.horizontalAlignment = SWT.RIGHT; + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalAlignment = SWT.LEFT; gd.verticalAlignment = SWT.CENTER; l.setLayoutData(gd); + + return l; } @Override protected void okPressed() { - if (mWriter != null) { - mWriter.stopTracing(); - } - + mRefreshTask.cancel(); super.okPressed(); } - public void setFrameCount(final int n) { - mFramesCollected = n; - scheduleDisplayUpdate(); - } + /** Periodically refresh the trace status. */ + private class StatusRefreshTask implements Runnable { + private static final int REFRESH_INTERVAL = 1000; + private volatile boolean mIsCancelled = false; - public void setTraceFileSize(final int n) { - mTraceFileSize = n; - scheduleDisplayUpdate(); - } + public void run() { + if (mTraceFileWriter == null) { + return; + } + + while (!mIsCancelled) { + final String frameCount = Integer.toString(mTraceFileWriter.getCurrentFrameCount()); + + double fileSize = (double) mTraceFileWriter.getCurrentFileSize(); + fileSize /= (1024 * 1024); // convert to size in MB + final String frameSize = String.format("%.2g MB", fileSize); //$NON-NLS-1$ - private Runnable mRefreshTask = null; + Display.getDefault().syncExec(new Runnable() { + public void run() { + if (mFramesCollectedLabel.isDisposed()) { + return; + } - /** Schedule a refresh UI task if one is not already pending. */ - private void scheduleDisplayUpdate() { - if (mRefreshTask == null) { - mRefreshTask = new Runnable() { - public void run() { - mRefreshTask = null; + mFramesCollectedLabel.setText(frameCount); + mTraceFileSizeLabel.setText(frameSize); - if (mFramesCollectedText.isDisposed()) { - return; + mFramesCollectedLabel.pack(); + mTraceFileSizeLabel.pack(); } + }); - mFramesCollectedText.setText(Integer.toString(mFramesCollected)); - mTraceFileSizeText.setText(Integer.toString(mTraceFileSize) + " bytes"); + try { + Thread.sleep(REFRESH_INTERVAL); + } catch (InterruptedException e) { + return; } - }; - Display.getDefault().asyncExec(mRefreshTask); + } } - } - public void setTraceWriter(GLTraceWriter writer) { - mWriter = writer; + public void cancel() { + mIsCancelled = true; + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java index 33d22ab..18f9968 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java @@ -29,6 +29,7 @@ import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; @@ -45,13 +46,10 @@ import org.osgi.service.prefs.BackingStoreException; import java.util.ArrayList; import java.util.List; -// FIXME: Not all elements in this dialog are functional. They are there for UI review, -// and once we figure out what needs to be there and what not, we'll fix this. /** Dialog displaying all the trace options before the user initiates tracing. */ public class GLTraceOptionsDialog extends TitleAreaDialog { - private static final String TITLE = "OpenGL ES 2.0 Trace Options"; - private static final String DEFAULT_MESSAGE = "Provide the application to be traced. The application needs to have INTERNET permission for tracing."; - private static final String DEFAULT_NUM_FRAMES_TEXT = "10"; + private static final String TITLE = "OpenGL ES Trace Options"; + private static final String DEFAULT_MESSAGE = "Provide the application and activity to be traced. The application needs to have INTERNET permission for tracing."; private static final String PREF_APPNAME = "gl.trace.appname"; private static final String PREF_TRACEFILE = "gl.trace.destfile"; @@ -61,13 +59,17 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { private Button mOkButton; private Combo mDeviceCombo; - private Text mAppToTraceText; + private Text mActivityToTraceText; private Text mTraceFilePathText; private String mSelectedDevice = ""; - private String mAppToTrace = ""; + private String mActivityToTrace = ""; private String mTraceFilePath = ""; + private boolean mCollectFbOnEglSwap = true; + private boolean mCollectFbOnGlDraw = false; + private boolean mCollectTextureData = false; + public GLTraceOptionsDialog(Shell parentShell) { super(parentShell); loadPreferences(); @@ -89,11 +91,8 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { createLabel(c, "Activity:"); createAppToTraceText(c, "e.g. com.example.android.apis"); - createLabel(c, "Capture Mode:"); - createCaptureModeOptions(c); - - createLabel(c, "Capture Framebuffer:"); - createCaptureFBOptions(c); + createLabel(c, "Capture Image:"); + createCaptureImageOptions(c); createSeparator(c); @@ -166,60 +165,51 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { } /** Options controlling when the FB should be captured. */ - private void createCaptureFBOptions(Composite parent) { + private void createCaptureImageOptions(Composite parent) { Composite c = new Composite(parent, SWT.NONE); c.setLayout(new GridLayout(1, false)); c.setLayoutData(new GridData(GridData.FILL_BOTH)); - Button b1 = new Button(c, SWT.CHECK); - b1.setText("On eglSwap()"); - b1.setSelection(true); + final Button readFbOnEglSwapCheckBox = new Button(c, SWT.CHECK); + readFbOnEglSwapCheckBox.setText("Read back framebuffer 0 on eglSwapBuffers()"); + readFbOnEglSwapCheckBox.setSelection(mCollectFbOnEglSwap); - Button b2 = new Button(c, SWT.CHECK); - b2.setText("On glDrawElements() and glDrawArrays()"); - b2.setSelection(false); - } + final Button readFbOnGlDrawCheckBox = new Button(c, SWT.CHECK); + readFbOnGlDrawCheckBox.setText("Read back currently bound framebuffer On glDraw*()"); + readFbOnGlDrawCheckBox.setSelection(mCollectFbOnGlDraw); - private void createCaptureModeOptions(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(2, false)); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); - - Button b1 = new Button(c, SWT.RADIO); - b1.setText("Infinite Buffer"); - GridData gd = new GridData(); - gd.horizontalSpan = 2; - b1.setLayoutData(gd); + final Button readTextureDataCheckBox = new Button(c, SWT.CHECK); + readTextureDataCheckBox.setText("Collect texture data submitted using glTexImage*()"); + readTextureDataCheckBox.setSelection(mCollectTextureData); - Button b2 = new Button(c, SWT.RADIO); - b2.setText("Last N frames"); - b2.setEnabled(false); - - b1.setSelection(true); + SelectionListener l = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + mCollectFbOnEglSwap = readFbOnEglSwapCheckBox.getSelection(); + mCollectFbOnGlDraw = readFbOnGlDrawCheckBox.getSelection(); + mCollectTextureData = readTextureDataCheckBox.getSelection(); + } + }; - Text t = new Text(c, SWT.BORDER); - t.setMessage(DEFAULT_NUM_FRAMES_TEXT); - gd = new GridData(); - gd.widthHint = 30; - t.setLayoutData(gd); - t.setEditable(false); - t.setEnabled(false); + readFbOnEglSwapCheckBox.addSelectionListener(l); + readFbOnGlDrawCheckBox.addSelectionListener(l); + readTextureDataCheckBox.addSelectionListener(l); } private Text createAppToTraceText(Composite parent, String defaultMessage) { - mAppToTraceText = new Text(parent, SWT.BORDER); - mAppToTraceText.setMessage(defaultMessage); - mAppToTraceText.setText(mAppToTrace); + mActivityToTraceText = new Text(parent, SWT.BORDER); + mActivityToTraceText.setMessage(defaultMessage); + mActivityToTraceText.setText(mActivityToTrace); - mAppToTraceText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mActivityToTraceText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mAppToTraceText.addModifyListener(new ModifyListener() { + mActivityToTraceText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { validateAndSetMessage(); } }); - return mAppToTraceText; + return mActivityToTraceText; } private void validateAndSetMessage() { @@ -269,7 +259,7 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { } private DialogStatus validateDialog() { - if (mAppToTraceText.getText().trim().length() == 0) { + if (mActivityToTraceText.getText().trim().length() == 0) { return new DialogStatus(false, "Provide an application name"); } @@ -282,7 +272,7 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { @Override protected void okPressed() { - mAppToTrace = mAppToTraceText.getText(); + mActivityToTrace = mActivityToTraceText.getText(); mTraceFilePath = mTraceFilePathText.getText(); mSelectedDevice = mDeviceCombo.getText(); @@ -293,7 +283,7 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { private void savePreferences() { IEclipsePreferences prefs = new InstanceScope().getNode(Activator.PLUGIN_ID); - prefs.put(PREF_APPNAME, mAppToTrace); + prefs.put(PREF_APPNAME, mActivityToTrace); prefs.put(PREF_TRACEFILE, mTraceFilePath); try { prefs.flush(); @@ -304,19 +294,12 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { private void loadPreferences() { IEclipsePreferences prefs = new InstanceScope().getNode(Activator.PLUGIN_ID); - mAppToTrace = prefs.get(PREF_APPNAME, ""); + mActivityToTrace = prefs.get(PREF_APPNAME, ""); mTraceFilePath = prefs.get(PREF_TRACEFILE, ""); } - public String getDevice() { - return mSelectedDevice; - } - - public String getApplicationToTrace() { - return mAppToTrace.trim(); - } - - public String getTraceDestination() { - return mTraceFilePath; + public TraceOptions getTraceOptions() { + return new TraceOptions(mSelectedDevice, mActivityToTrace.trim(), mTraceFilePath, + mCollectFbOnEglSwap, mCollectFbOnGlDraw, mCollectTextureData); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceCommandWriter.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceCommandWriter.java new file mode 100644 index 0000000..f8d97b7 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceCommandWriter.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.gltrace; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Write trace control options to the trace backend. + * Currently, the number of options is limited, so all the options are packed into a + * single integer. Any changes to this protocol have to be updated on the device as well. + */ +public class TraceCommandWriter { + private static final int READ_FB_ON_EGLSWAP_BIT = 0; + private static final int READ_FB_ON_GLDRAW_BIT = 1; + private static final int READ_TEXTURE_DATA_ON_GLTEXIMAGE_BIT = 2; + + private final DataOutputStream mStream;; + + public TraceCommandWriter(DataOutputStream traceCommandStream) { + mStream = traceCommandStream; + } + + public void setTraceOptions(boolean readFbOnEglSwap, boolean readFbOnGlDraw, + boolean readTextureOnGlTexImage) throws IOException { + int eglSwap = readFbOnEglSwap ? (1 << READ_FB_ON_EGLSWAP_BIT) : 0; + int glDraw = readFbOnGlDraw ? (1 << READ_FB_ON_GLDRAW_BIT) : 0; + int tex = readTextureOnGlTexImage ? ( 1 << READ_TEXTURE_DATA_ON_GLTEXIMAGE_BIT) : 0; + + int cmd = eglSwap | glDraw | tex; + + mStream.writeInt(cmd); + mStream.flush(); + } + + public void close() { + try { + mStream.close(); + } catch (IOException e) { + // ignore exception while closing stream + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceWriter.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileWriter.java index d57d677..a6c02c4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceWriter.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileWriter.java @@ -17,30 +17,31 @@ package com.android.ide.eclipse.gltrace; import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage; +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function; import com.google.protobuf.InvalidProtocolBufferException; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.net.Socket; /** A class that streams data received from a socket into the trace file. */ -public class GLTraceWriter { +public class TraceFileWriter { + private DataInputStream mInputStream; private DataOutputStream mOutputStream; - private int mPort; - private GLTraceCollectorDialog mDialog; - private volatile boolean stopTracing = false; private Thread mReceiverThread; private int mFileSize = 0; private int mFrameCount = 0; - public GLTraceWriter(FileOutputStream fos, int port, - GLTraceCollectorDialog glTraceCollectorDialog) { + /** + * Construct a trace file writer. + * @param fos output stream to write trace data to + * @param is input stream from which trace data is read + */ + public TraceFileWriter(FileOutputStream fos, DataInputStream is) { mOutputStream = new DataOutputStream(fos); - mPort = port; - mDialog = glTraceCollectorDialog; + mInputStream = is; } public void start() { @@ -48,15 +49,15 @@ public class GLTraceWriter { mReceiverThread = new Thread(new GLTraceReceiverTask()); mReceiverThread.setName("GL Trace Receiver"); mReceiverThread.start(); - - // launch dialog - mDialog.setTraceWriter(this); - mDialog.open(); } public void stopTracing() { - // stop thread - stopTracing = true; + // close socket to stop the receiver thread + try { + mInputStream.close(); + } catch (IOException e) { + // ignore exception while closing socket + } // wait for receiver to complete try { @@ -73,62 +74,82 @@ public class GLTraceWriter { } } + /** + * The GLTraceReceiverTask collects trace data from the device and writes it + * into a file while collecting some stats on the way. + */ private class GLTraceReceiverTask implements Runnable { public void run() { - try { - Socket socket = new Socket(); - socket.connect(new java.net.InetSocketAddress("127.0.0.1", mPort)); - DataInputStream dis = new DataInputStream(socket.getInputStream()); - - while (!stopTracing) { - if (dis.available() > 0) { - readMessage(dis); - mDialog.setFrameCount(mFrameCount); - mDialog.setTraceFileSize(mFileSize); - } else { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - // ignore, as this thread is not interrupted by any other thread. - } - } + while (true) { + byte[] buffer = readTraceData(mInputStream); + if (buffer == null) { + break; } - socket.close(); - } catch (IOException e) { + try { + writeTraceData(buffer, mOutputStream); + } catch (IOException e) { + break; + } + + updateTraceStats(buffer); } } } - private void readMessage(DataInputStream dis) throws IOException { - int len = dis.readInt(); + private byte[] readTraceData(DataInputStream dis) { + int len; + try { + len = dis.readInt(); + } catch (IOException e1) { + return null; + } len = Integer.reverseBytes(len); // readInt is big endian, we want little endian byte[] buffer = new byte[len]; int readLen = 0; while (readLen < len) { - int read = dis.read(buffer, readLen, len - readLen); - if (read < 0) { - throw new IOException(); - } else { - readLen += read; + try { + int read = dis.read(buffer, readLen, len - readLen); + if (read < 0) { + return null; + } else { + readLen += read; + } + } catch (IOException e) { + return null; } } + return buffer; + } + + + private void writeTraceData(byte[] buffer, DataOutputStream stream) throws IOException { + stream.writeInt(buffer.length); + stream.write(buffer); + } + + private void updateTraceStats(byte[] buffer) { GLMessage msg = null; try { msg = GLMessage.parseFrom(buffer); } catch (InvalidProtocolBufferException e) { - System.out.println("Invalid protocol buffer: " + e.getMessage()); return; } - mOutputStream.writeInt(len); - mOutputStream.write(buffer); - mFileSize += readLen; + mFileSize += buffer.length; - if (msg.getFunction() == GLMessage.Function.eglSwapBuffers) { + if (msg.getFunction() == Function.eglSwapBuffers) { mFrameCount++; } } + + public int getCurrentFileSize() { + return mFileSize; + } + + public int getCurrentFrameCount() { + return mFrameCount; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java new file mode 100644 index 0000000..d67d167 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.gltrace; + +public class TraceOptions { + /** Device on which the application should be run. */ + public final String device; + + /** Activity to trace. */ + public final String activityToTrace; + + /** Path where the trace file should be saved. */ + public final String traceDestination; + + /** Flag indicating whether Framebuffer should be captured on eglSwap() */ + public final boolean collectFbOnEglSwap; + + /** Flag indicating whether Framebuffer should be captured on glDraw*() */ + public final boolean collectFbOnGlDraw; + + /** Flag indicating whether texture data should be captured on glTexImage*() */ + public final boolean collectTextureData; + + public TraceOptions(String device, String activity, String destinationPath, + boolean collectFbOnEglSwap, boolean collectFbOnGlDraw, boolean collectTextureData) { + this.device = device; + this.activityToTrace = activity; + this.traceDestination = destinationPath; + this.collectFbOnEglSwap = collectFbOnEglSwap; + this.collectFbOnGlDraw = collectFbOnGlDraw; + this.collectTextureData = collectTextureData; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java index fc6ce18..31d48c8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java @@ -260,7 +260,21 @@ public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvi tvc.setLabelProvider(labelProvider); TableColumn column = tvc.getColumn(); column.setText("Context"); - column.setWidth(50); + column.setWidth(150); + + // column showing the GL function called + tvc = new TableViewerColumn(mFrameTableViewer, SWT.NONE); + tvc.setLabelProvider(labelProvider); + column = tvc.getColumn(); + column.setText("Start"); + column.setWidth(150); + + // column showing the GL function called + tvc = new TableViewerColumn(mFrameTableViewer, SWT.NONE); + tvc.setLabelProvider(labelProvider); + column = tvc.getColumn(); + column.setText("Duration"); + column.setWidth(150); // column showing the GL function called tvc = new TableViewerColumn(mFrameTableViewer, SWT.NONE); @@ -359,6 +373,10 @@ public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvi switch (columnIndex) { case 0: return Integer.toString(c.getContextId()); + case 1: + return Long.toString(c.getStartTime()); + case 2: + return Integer.toString(c.getDuration()); default: try { return sGLCallFormatter.formatGLCall(c); diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java index c868bde..98b1db6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java @@ -101,4 +101,12 @@ public class GLCall { public Image getThumbnailImage() { return mThumbnailImage; } + + public long getStartTime() { + return mMessage.getStartTime(); + } + + public int getDuration() { + return mMessage.getDuration(); + } } |