aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java428
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/DeviceViewAction.java113
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/FileUtils.java42
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLEnum.java1017
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLProtoBuf.java3119
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceCollectorDialog.java228
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java403
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java56
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLUtils.java110
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GlTracePlugin.java130
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/OpenGLTraceAction.java88
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/ProtoBufUtils.java86
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/SwtUtils.java33
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceCommandWriter.java60
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileInfo.java41
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java254
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileReader.java66
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileWriter.java156
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java55
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/DurationMinimap.java541
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java202
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java984
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateContentProvider.java75
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateLabelProvider.java103
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateViewPage.java372
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLAPISpec.java134
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLDataTypeSpec.java75
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLMessageFormatter.java166
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java183
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLFrame.java51
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLTrace.java120
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/DisplayRadix.java21
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLAbstractAtomicProperty.java65
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLBooleanProperty.java64
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLCompositeProperty.java136
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLEnumProperty.java64
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLFloatProperty.java63
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLIntegerProperty.java73
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLListProperty.java182
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLLongProperty.java73
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLObjectProperty.java66
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLSparseArrayProperty.java170
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLState.java402
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStateType.java187
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStringProperty.java62
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/IGLProperty.java63
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/StatePrettyPrinter.java67
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/BufferSubDataTransform.java76
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentProgramPropertyAccessor.java67
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentVboPropertyAccessor.java71
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/GLPropertyAccessor.java139
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IGLPropertyAccessor.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IPredicate.java21
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IStateTransform.java34
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/ListElementAddTransform.java69
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/Predicates.java36
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/PropertyChangeTransform.java103
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementAddTransform.java77
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementRemoveTransform.java49
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java1384
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexImageTransform.java342
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexturePropertyAccessor.java86
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TextureUnitPropertyAccessor.java64
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FitToCanvasAction.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryView.java53
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java442
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/GLPageBookView.java83
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/SaveImageAction.java59
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/StateView.java57
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsPage.java232
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsView.java52
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/GlDrawCallDetailProvider.java82
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ICallDetailProvider.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IDetailProvider.java38
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IStateDetailProvider.java27
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderSourceDetailsProvider.java103
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderUniformDetailsProvider.java173
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/TextureImageDetailsProvider.java158
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VboDetailProvider.java189
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/VertexAttribPointerDataDetailProvider.java72
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/widgets/ImageCanvas.java250
81 files changed, 16039 insertions, 0 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
new file mode 100644
index 000000000..c13ab461b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java
@@ -0,0 +1,428 @@
+/*
+ * 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 com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.IDevice.DeviceUnixSocketNamespace;
+import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.TimeoutException;
+import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer;
+import com.google.common.io.Closeables;
+import com.google.common.util.concurrent.SimpleTimeLimiter;
+
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.ide.IDE;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public class CollectTraceAction implements IWorkbenchWindowActionDelegate {
+ /** Abstract Unix Domain Socket Name used by the gltrace device code. */
+ private static final String GLTRACE_UDS = "gltrace"; //$NON-NLS-1$
+
+ /** Local port that is forwarded to the device's {@link #GLTRACE_UDS} socket. */
+ private static final int LOCAL_FORWARDED_PORT = 6039;
+
+ /** Activity name to use for a system activity that has already been launched. */
+ private static final String SYSTEM_APP = "system"; //$NON-NLS-1$
+
+ /** Time to wait for the application to launch (seconds) */
+ private static final int LAUNCH_TIMEOUT = 15;
+
+ /** Time to wait for the application to die (seconds) */
+ private static final int KILL_TIMEOUT = 5;
+
+ private static final int MIN_API_LEVEL = 16;
+
+ @Override
+ public void run(IAction action) {
+ connectToDevice();
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void init(IWorkbenchWindow window) {
+ }
+
+ private void connectToDevice() {
+ Shell shell = Display.getDefault().getActiveShell();
+ GLTraceOptionsDialog dlg = new GLTraceOptionsDialog(shell);
+ if (dlg.open() != Window.OK) {
+ return;
+ }
+
+ TraceOptions traceOptions = dlg.getTraceOptions();
+
+ IDevice device = getDevice(traceOptions.device);
+ String apiLevelString = device.getProperty(IDevice.PROP_BUILD_API_LEVEL);
+ int apiLevel;
+ try {
+ apiLevel = Integer.parseInt(apiLevelString);
+ } catch (NumberFormatException e) {
+ apiLevel = MIN_API_LEVEL;
+ }
+ if (apiLevel < MIN_API_LEVEL) {
+ MessageDialog.openError(shell, "GL Trace",
+ String.format("OpenGL Tracing is only supported on devices at API Level %1$d."
+ + "The selected device '%2$s' provides API level %3$s.",
+ MIN_API_LEVEL, traceOptions.device, apiLevelString));
+ return;
+ }
+
+ try {
+ setupForwarding(device, LOCAL_FORWARDED_PORT);
+ } catch (Exception e) {
+ MessageDialog.openError(shell, "Setup GL Trace",
+ "Error while setting up port forwarding: " + e.getMessage());
+ return;
+ }
+
+ try {
+ if (!SYSTEM_APP.equals(traceOptions.appToTrace)) {
+ startActivity(device, traceOptions.appToTrace, traceOptions.activityToTrace,
+ traceOptions.isActivityNameFullyQualified);
+ }
+ } catch (Exception e) {
+ MessageDialog.openError(shell, "Setup GL Trace",
+ "Error while launching application: " + e.getMessage());
+ return;
+ }
+
+ // if everything went well, the app should now be waiting for the gl debugger
+ // to connect
+ startTracing(shell, traceOptions, LOCAL_FORWARDED_PORT);
+
+ // once tracing is complete, remove port forwarding
+ disablePortForwarding(device, LOCAL_FORWARDED_PORT);
+
+ // and finally open the editor to view the file
+ openInEditor(shell, traceOptions.traceDestination);
+ }
+
+ public static void openInEditor(Shell shell, String traceFilePath) {
+ final IFileStore fileStore = EFS.getLocalFileSystem().getStore(new Path(traceFilePath));
+ if (!fileStore.fetchInfo().exists()) {
+ return;
+ }
+
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+ if (window == null) {
+ return;
+ }
+
+ IWorkbenchPage page = window.getActivePage();
+ if (page == null) {
+ return;
+ }
+
+ try {
+ workbench.showPerspective("com.android.ide.eclipse.gltrace.perspective", window);
+ } catch (WorkbenchException e) {
+ }
+
+ // if there is a editor already open, then refresh its model
+ GLFunctionTraceViewer viewer = getOpenTraceViewer(page, traceFilePath);
+ if (viewer != null) {
+ viewer.setInput(shell, traceFilePath);
+ }
+
+ // open the editor (if not open), or bring it to foreground if it is already open
+ try {
+ IDE.openEditorOnFileStore(page, fileStore);
+ } catch (PartInitException e) {
+ GlTracePlugin.getDefault().logMessage(
+ "Unexpected error while opening gltrace file in editor: " + e);
+ return;
+ }
+ }
+
+ /**
+ * Returns the editor part that has the provided file path open.
+ * @param page page containing editors
+ * @param traceFilePath file that should be open in an editor
+ * @return if given trace file is already open, then a reference to that editor part,
+ * null otherwise
+ */
+ private static GLFunctionTraceViewer getOpenTraceViewer(IWorkbenchPage page,
+ String traceFilePath) {
+ IEditorReference[] editorRefs = page.getEditorReferences();
+ for (IEditorReference ref : editorRefs) {
+ String id = ref.getId();
+ if (!GLFunctionTraceViewer.ID.equals(id)) {
+ continue;
+ }
+
+ IEditorInput input = null;
+ try {
+ input = ref.getEditorInput();
+ } catch (PartInitException e) {
+ continue;
+ }
+
+ if (!(input instanceof IURIEditorInput)) {
+ continue;
+ }
+
+ if (traceFilePath.equals(((IURIEditorInput) input).getURI().getPath())) {
+ return (GLFunctionTraceViewer) ref.getEditor(true);
+ }
+ }
+
+ return null;
+ }
+
+ @SuppressWarnings("resource") // Closeables.closeQuietly
+ public static void startTracing(Shell shell, TraceOptions traceOptions, int port) {
+ 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;
+ }
+
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(traceOptions.traceDestination, false);
+ } catch (FileNotFoundException e) {
+ // input path is valid, so this cannot occur
+ }
+
+ // 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 static void closeSocket(Socket socket) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ // ignore error while closing socket
+ }
+ }
+
+ private void startActivity(IDevice device, String appPackage, String activity,
+ boolean isActivityNameFullyQualified)
+ throws TimeoutException, AdbCommandRejectedException,
+ ShellCommandUnresponsiveException, IOException, InterruptedException {
+ killApp(device, appPackage); // kill app if it is already running
+ waitUntilAppKilled(device, appPackage, KILL_TIMEOUT);
+
+ StringBuilder activityPath = new StringBuilder(appPackage);
+ if (!activity.isEmpty()) {
+ activityPath.append('/');
+ if (!isActivityNameFullyQualified) {
+ activityPath.append('.');
+ }
+ activityPath.append(activity);
+ }
+ String startAppCmd = String.format(
+ "am start --opengl-trace %s -a android.intent.action.MAIN -c android.intent.category.LAUNCHER", //$NON-NLS-1$
+ activityPath.toString());
+
+ Semaphore launchCompletionSempahore = new Semaphore(0);
+ StartActivityOutputReceiver receiver = new StartActivityOutputReceiver(
+ launchCompletionSempahore);
+ device.executeShellCommand(startAppCmd, receiver);
+
+ // wait until shell finishes launch command
+ launchCompletionSempahore.acquire();
+
+ // throw exception if there was an error during launch
+ String output = receiver.getOutput();
+ if (output.contains("Error")) { //$NON-NLS-1$
+ throw new RuntimeException(output);
+ }
+
+ // wait until the app itself has been launched
+ waitUntilAppLaunched(device, appPackage, LAUNCH_TIMEOUT);
+ }
+
+ private void killApp(IDevice device, String appName) {
+ Client client = device.getClient(appName);
+ if (client != null) {
+ client.kill();
+ }
+ }
+
+ private void waitUntilAppLaunched(final IDevice device, final String appName, int timeout) {
+ Callable<Boolean> c = new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ Client client;
+ do {
+ client = device.getClient(appName);
+ } while (client == null);
+
+ return Boolean.TRUE;
+ }
+ };
+ try {
+ new SimpleTimeLimiter().callWithTimeout(c, timeout, TimeUnit.SECONDS, true);
+ } catch (Exception e) {
+ throw new RuntimeException("Timed out waiting for application to launch.");
+ }
+
+ // once the app has launched, wait an additional couple of seconds
+ // for it to start up
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ private void waitUntilAppKilled(final IDevice device, final String appName, int timeout) {
+ Callable<Boolean> c = new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ Client client;
+ while ((client = device.getClient(appName)) != null) {
+ client.kill();
+ }
+ return Boolean.TRUE;
+ }
+ };
+ try {
+ new SimpleTimeLimiter().callWithTimeout(c, timeout, TimeUnit.SECONDS, true);
+ } catch (Exception e) {
+ throw new RuntimeException("Timed out waiting for running application to die.");
+ }
+ }
+
+ public static void setupForwarding(IDevice device, int i)
+ throws TimeoutException, AdbCommandRejectedException, IOException {
+ device.createForward(i, GLTRACE_UDS, DeviceUnixSocketNamespace.ABSTRACT);
+ }
+
+ public static void disablePortForwarding(IDevice device, int port) {
+ try {
+ device.removeForward(port, GLTRACE_UDS, DeviceUnixSocketNamespace.ABSTRACT);
+ } catch (Exception e) {
+ // ignore exceptions;
+ }
+ }
+
+ private IDevice getDevice(String deviceName) {
+ IDevice[] devices = AndroidDebugBridge.getBridge().getDevices();
+
+ for (IDevice device : devices) {
+ if (device.getName().equals(deviceName)) {
+ return device;
+ }
+ }
+
+ return null;
+ }
+
+ private static class StartActivityOutputReceiver implements IShellOutputReceiver {
+ private Semaphore mSemaphore;
+ private StringBuffer sb = new StringBuffer(300);
+
+ public StartActivityOutputReceiver(Semaphore s) {
+ mSemaphore = s;
+ }
+
+ @Override
+ public void addOutput(byte[] data, int offset, int length) {
+ String d = new String(data, offset, length);
+ sb.append(d);
+ }
+
+ @Override
+ public void flush() {
+ mSemaphore.release();
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ public String getOutput() {
+ return sb.toString();
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/DeviceViewAction.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/DeviceViewAction.java
new file mode 100644
index 000000000..7d912bafe
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/DeviceViewAction.java
@@ -0,0 +1,113 @@
+package com.android.ide.eclipse.gltrace;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData;
+import com.android.ide.eclipse.ddms.IClientAction;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import java.lang.reflect.InvocationTargetException;
+
+public class DeviceViewAction implements IClientAction {
+ private static final class StartTraceAction extends Action {
+ private static final int LOCAL_FORWARDED_PORT = 6049;
+
+ private Client mClient;
+
+ public StartTraceAction() {
+ super("Start OpenGL Trace");
+ setImageDescriptor(GlTracePlugin.getImageDescriptor("/icons/connect.png")); //$NON-NLS-1$
+ setClient(null);
+ }
+
+ public void setClient(Client c) {
+ mClient = c;
+ clientChanged();
+ }
+
+ private void clientChanged() {
+ if (mClient == null) {
+ setEnabled(false);
+ return;
+ }
+
+ ClientData cd = mClient.getClientData();
+ if (cd.hasFeature(ClientData.FEATURE_OPENGL_TRACING)) {
+ setEnabled(true);
+ setToolTipText("Trace OpenGL calls");
+ } else {
+ setEnabled(false);
+ setToolTipText("Selected VM does not support tracing OpenGL calls");
+ }
+ }
+
+ @Override
+ public void run() {
+ if (mClient == null) {
+ return;
+ }
+
+ Shell shell = Display.getDefault().getActiveShell();
+ GLTraceOptionsDialog dlg = new GLTraceOptionsDialog(shell, false,
+ mClient.getClientData().getClientDescription());
+ if (dlg.open() != Window.OK) {
+ return;
+ }
+
+ // start tracing on the client
+ mClient.startOpenGlTracing();
+
+ try {
+ CollectTraceAction.setupForwarding(mClient.getDevice(), LOCAL_FORWARDED_PORT);
+ } catch (Exception e) {
+ MessageDialog.openError(shell, "Setup GL Trace",
+ "Error while setting up port forwarding: " + e.getMessage());
+ return;
+ }
+
+ // wait for a few seconds for the client to start the trace server
+ try {
+ new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
+ @Override
+ public void run(IProgressMonitor monitor)
+ throws InvocationTargetException, InterruptedException {
+ Thread.sleep(3000);
+ }
+ });
+ } catch (Exception e) {
+ }
+
+ // retrieve the trace from the device
+ TraceOptions traceOptions = dlg.getTraceOptions();
+ CollectTraceAction.startTracing(shell, traceOptions, LOCAL_FORWARDED_PORT);
+
+ // inform the client that it doesn't need to be traced anymore
+ mClient.stopOpenGlTracing();
+
+ // remove port forwarding
+ CollectTraceAction.disablePortForwarding(mClient.getDevice(), LOCAL_FORWARDED_PORT);
+
+ // and finally open the editor to view the file
+ CollectTraceAction.openInEditor(shell, traceOptions.traceDestination);
+ }
+ }
+
+ private static final StartTraceAction sAction = new StartTraceAction();
+
+ @Override
+ public Action getAction() {
+ return sAction;
+ }
+
+ @Override
+ public void selectedClientChanged(Client c) {
+ sAction.setClient(c);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/FileUtils.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/FileUtils.java
new file mode 100644
index 000000000..ab06f6757
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/FileUtils.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.io.IOException;
+
+public class FileUtils {
+ private static final File sCacheDir;
+
+ static {
+ sCacheDir = Files.createTempDir();
+ sCacheDir.deleteOnExit();
+ }
+
+ public static File createTempFile(String prefix, String suffix) {
+ File f;
+ try {
+ f = File.createTempFile(prefix, suffix, sCacheDir);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ f.deleteOnExit();
+ return f;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLEnum.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLEnum.java
new file mode 100644
index 000000000..ceb9f1a51
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLEnum.java
@@ -0,0 +1,1017 @@
+/*
+ ** Copyright 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.
+ */
+
+// auto generated by generate_GLEnum_java.py"
+
+package com.android.ide.eclipse.gltrace;
+
+public enum GLEnum {
+ GL_NONE(0x0000),
+ GL_LINES(0x0001),
+ GL_LINE_LOOP(0x0002),
+ GL_LINE_STRIP(0x0003),
+ GL_TRIANGLES(0x0004),
+ GL_TRIANGLE_STRIP(0x0005),
+ GL_TRIANGLE_FAN(0x0006),
+ GL_ADD(0x0104),
+ GL_NEVER(0x0200),
+ GL_LESS(0x0201),
+ GL_EQUAL(0x0202),
+ GL_LEQUAL(0x0203),
+ GL_GREATER(0x0204),
+ GL_NOTEQUAL(0x0205),
+ GL_GEQUAL(0x0206),
+ GL_ALWAYS(0x0207),
+ GL_SRC_COLOR(0x0300),
+ GL_ONE_MINUS_SRC_COLOR(0x0301),
+ GL_SRC_ALPHA(0x0302),
+ GL_ONE_MINUS_SRC_ALPHA(0x0303),
+ GL_DST_ALPHA(0x0304),
+ GL_ONE_MINUS_DST_ALPHA(0x0305),
+ GL_DST_COLOR(0x0306),
+ GL_ONE_MINUS_DST_COLOR(0x0307),
+ GL_SRC_ALPHA_SATURATE(0x0308),
+ GL_FRONT(0x0404),
+ GL_BACK(0x0405),
+ GL_FRONT_AND_BACK(0x0408),
+ GL_INVALID_ENUM(0x0500),
+ GL_INVALID_VALUE(0x0501),
+ GL_INVALID_OPERATION(0x0502),
+ GL_STACK_OVERFLOW(0x0503),
+ GL_STACK_UNDERFLOW(0x0504),
+ GL_OUT_OF_MEMORY(0x0505),
+ GL_INVALID_FRAMEBUFFER_OPERATION(0x0506),
+ GL_EXP(0x0800),
+ GL_EXP2(0x0801),
+ GL_CW(0x0900),
+ GL_CCW(0x0901),
+ GL_CURRENT_COLOR(0x0B00),
+ GL_CURRENT_NORMAL(0x0B02),
+ GL_CURRENT_TEXTURE_COORDS(0x0B03),
+ GL_POINT_SMOOTH(0x0B10),
+ GL_POINT_SIZE(0x0B11),
+ GL_SMOOTH_POINT_SIZE_RANGE(0x0B12),
+ GL_LINE_SMOOTH(0x0B20),
+ GL_LINE_WIDTH(0x0B21),
+ GL_SMOOTH_LINE_WIDTH_RANGE(0x0B22),
+ GL_CULL_FACE(0x0B44),
+ GL_CULL_FACE_MODE(0x0B45),
+ GL_FRONT_FACE(0x0B46),
+ GL_LIGHTING(0x0B50),
+ GL_LIGHT_MODEL_TWO_SIDE(0x0B52),
+ GL_LIGHT_MODEL_AMBIENT(0x0B53),
+ GL_SHADE_MODEL(0x0B54),
+ GL_COLOR_MATERIAL(0x0B57),
+ GL_FOG(0x0B60),
+ GL_FOG_DENSITY(0x0B62),
+ GL_FOG_START(0x0B63),
+ GL_FOG_END(0x0B64),
+ GL_FOG_MODE(0x0B65),
+ GL_FOG_COLOR(0x0B66),
+ GL_DEPTH_RANGE(0x0B70),
+ GL_DEPTH_TEST(0x0B71),
+ GL_DEPTH_WRITEMASK(0x0B72),
+ GL_DEPTH_CLEAR_VALUE(0x0B73),
+ GL_DEPTH_FUNC(0x0B74),
+ GL_STENCIL_TEST(0x0B90),
+ GL_STENCIL_CLEAR_VALUE(0x0B91),
+ GL_STENCIL_FUNC(0x0B92),
+ GL_STENCIL_VALUE_MASK(0x0B93),
+ GL_STENCIL_FAIL(0x0B94),
+ GL_STENCIL_PASS_DEPTH_FAIL(0x0B95),
+ GL_STENCIL_PASS_DEPTH_PASS(0x0B96),
+ GL_STENCIL_REF(0x0B97),
+ GL_STENCIL_WRITEMASK(0x0B98),
+ GL_MATRIX_MODE(0x0BA0),
+ GL_NORMALIZE(0x0BA1),
+ GL_VIEWPORT(0x0BA2),
+ GL_MODELVIEW_STACK_DEPTH(0x0BA3),
+ GL_PROJECTION_STACK_DEPTH(0x0BA4),
+ GL_TEXTURE_STACK_DEPTH(0x0BA5),
+ GL_MODELVIEW_MATRIX(0x0BA6),
+ GL_PROJECTION_MATRIX(0x0BA7),
+ GL_TEXTURE_MATRIX(0x0BA8),
+ GL_ALPHA_TEST(0x0BC0),
+ GL_ALPHA_TEST_FUNC(0x0BC1),
+ GL_ALPHA_TEST_REF(0x0BC2),
+ GL_DITHER(0x0BD0),
+ GL_BLEND_DST(0x0BE0),
+ GL_BLEND_SRC(0x0BE1),
+ GL_BLEND(0x0BE2),
+ GL_LOGIC_OP_MODE(0x0BF0),
+ GL_COLOR_LOGIC_OP(0x0BF2),
+ GL_READ_BUFFER_NV(0x0C02),
+ GL_SCISSOR_BOX(0x0C10),
+ GL_SCISSOR_TEST(0x0C11),
+ GL_COLOR_CLEAR_VALUE(0x0C22),
+ GL_COLOR_WRITEMASK(0x0C23),
+ GL_PERSPECTIVE_CORRECTION_HINT(0x0C50),
+ GL_POINT_SMOOTH_HINT(0x0C51),
+ GL_LINE_SMOOTH_HINT(0x0C52),
+ GL_FOG_HINT(0x0C54),
+ GL_UNPACK_ROW_LENGTH(0x0CF2),
+ GL_UNPACK_SKIP_ROWS(0x0CF3),
+ GL_UNPACK_SKIP_PIXELS(0x0CF4),
+ GL_UNPACK_ALIGNMENT(0x0CF5),
+ GL_PACK_ALIGNMENT(0x0D05),
+ GL_ALPHA_SCALE(0x0D1C),
+ GL_MAX_LIGHTS(0x0D31),
+ GL_MAX_CLIP_PLANES(0x0D32),
+ GL_MAX_TEXTURE_SIZE(0x0D33),
+ GL_MAX_MODELVIEW_STACK_DEPTH(0x0D36),
+ GL_MAX_PROJECTION_STACK_DEPTH(0x0D38),
+ GL_MAX_TEXTURE_STACK_DEPTH(0x0D39),
+ GL_MAX_VIEWPORT_DIMS(0x0D3A),
+ GL_SUBPIXEL_BITS(0x0D50),
+ GL_RED_BITS(0x0D52),
+ GL_GREEN_BITS(0x0D53),
+ GL_BLUE_BITS(0x0D54),
+ GL_ALPHA_BITS(0x0D55),
+ GL_DEPTH_BITS(0x0D56),
+ GL_STENCIL_BITS(0x0D57),
+ GL_TEXTURE_2D(0x0DE1),
+ GL_DONT_CARE(0x1100),
+ GL_FASTEST(0x1101),
+ GL_NICEST(0x1102),
+ GL_AMBIENT(0x1200),
+ GL_DIFFUSE(0x1201),
+ GL_SPECULAR(0x1202),
+ GL_POSITION(0x1203),
+ GL_SPOT_DIRECTION(0x1204),
+ GL_SPOT_EXPONENT(0x1205),
+ GL_SPOT_CUTOFF(0x1206),
+ GL_CONSTANT_ATTENUATION(0x1207),
+ GL_LINEAR_ATTENUATION(0x1208),
+ GL_QUADRATIC_ATTENUATION(0x1209),
+ GL_BYTE(0x1400),
+ GL_UNSIGNED_BYTE(0x1401),
+ GL_SHORT(0x1402),
+ GL_UNSIGNED_SHORT(0x1403),
+ GL_INT(0x1404),
+ GL_UNSIGNED_INT(0x1405),
+ GL_FLOAT(0x1406),
+ GL_FIXED(0x140C),
+ GL_CLEAR(0x1500),
+ GL_AND(0x1501),
+ GL_AND_REVERSE(0x1502),
+ GL_COPY(0x1503),
+ GL_AND_INVERTED(0x1504),
+ GL_NOOP(0x1505),
+ GL_XOR(0x1506),
+ GL_OR(0x1507),
+ GL_NOR(0x1508),
+ GL_EQUIV(0x1509),
+ GL_INVERT(0x150A),
+ GL_OR_REVERSE(0x150B),
+ GL_COPY_INVERTED(0x150C),
+ GL_OR_INVERTED(0x150D),
+ GL_NAND(0x150E),
+ GL_SET(0x150F),
+ GL_EMISSION(0x1600),
+ GL_SHININESS(0x1601),
+ GL_AMBIENT_AND_DIFFUSE(0x1602),
+ GL_MODELVIEW(0x1700),
+ GL_PROJECTION(0x1701),
+ GL_TEXTURE(0x1702),
+ GL_COLOR_EXT(0x1800),
+ GL_DEPTH_EXT(0x1801),
+ GL_STENCIL_EXT(0x1802),
+ GL_STENCIL_INDEX(0x1901),
+ GL_DEPTH_COMPONENT(0x1902),
+ GL_RED_EXT(0x1903),
+ GL_ALPHA(0x1906),
+ GL_RGB(0x1907),
+ GL_RGBA(0x1908),
+ GL_LUMINANCE(0x1909),
+ GL_LUMINANCE_ALPHA(0x190A),
+ GL_FLAT(0x1D00),
+ GL_SMOOTH(0x1D01),
+ GL_KEEP(0x1E00),
+ GL_REPLACE(0x1E01),
+ GL_INCR(0x1E02),
+ GL_DECR(0x1E03),
+ GL_VENDOR(0x1F00),
+ GL_RENDERER(0x1F01),
+ GL_VERSION(0x1F02),
+ GL_EXTENSIONS(0x1F03),
+ GL_MODULATE(0x2100),
+ GL_DECAL(0x2101),
+ GL_TEXTURE_ENV_MODE(0x2200),
+ GL_TEXTURE_ENV_COLOR(0x2201),
+ GL_TEXTURE_ENV(0x2300),
+ GL_TEXTURE_GEN_MODE(0x2500),
+ GL_NEAREST(0x2600),
+ GL_LINEAR(0x2601),
+ GL_NEAREST_MIPMAP_NEAREST(0x2700),
+ GL_LINEAR_MIPMAP_NEAREST(0x2701),
+ GL_NEAREST_MIPMAP_LINEAR(0x2702),
+ GL_LINEAR_MIPMAP_LINEAR(0x2703),
+ GL_TEXTURE_MAG_FILTER(0x2800),
+ GL_TEXTURE_MIN_FILTER(0x2801),
+ GL_TEXTURE_WRAP_S(0x2802),
+ GL_TEXTURE_WRAP_T(0x2803),
+ GL_REPEAT(0x2901),
+ GL_POLYGON_OFFSET_UNITS(0x2A00),
+ GL_CLIP_PLANE0(0x3000),
+ GL_CLIP_PLANE1(0x3001),
+ GL_CLIP_PLANE2(0x3002),
+ GL_CLIP_PLANE3(0x3003),
+ GL_CLIP_PLANE4(0x3004),
+ GL_CLIP_PLANE5(0x3005),
+ GL_LIGHT0(0x4000),
+ GL_LIGHT1(0x4001),
+ GL_LIGHT2(0x4002),
+ GL_LIGHT3(0x4003),
+ GL_LIGHT4(0x4004),
+ GL_LIGHT5(0x4005),
+ GL_LIGHT6(0x4006),
+ GL_LIGHT7(0x4007),
+ GL_COVERAGE_BUFFER_BIT_NV(0x8000),
+ GL_CONSTANT_COLOR(0x8001),
+ GL_ONE_MINUS_CONSTANT_COLOR(0x8002),
+ GL_CONSTANT_ALPHA(0x8003),
+ GL_ONE_MINUS_CONSTANT_ALPHA(0x8004),
+ GL_BLEND_COLOR(0x8005),
+ GL_FUNC_ADD(0x8006),
+ GL_MIN_EXT(0x8007),
+ GL_MAX_EXT(0x8008),
+ GL_BLEND_EQUATION_RGB(0x8009),
+ GL_FUNC_SUBTRACT(0x800A),
+ GL_FUNC_REVERSE_SUBTRACT(0x800B),
+ GL_UNSIGNED_SHORT_4_4_4_4(0x8033),
+ GL_UNSIGNED_SHORT_5_5_5_1(0x8034),
+ GL_POLYGON_OFFSET_FILL(0x8037),
+ GL_POLYGON_OFFSET_FACTOR(0x8038),
+ GL_RESCALE_NORMAL(0x803A),
+ GL_ALPHA8_EXT(0x803C),
+ GL_LUMINANCE8_EXT(0x8040),
+ GL_LUMINANCE8_ALPHA8_EXT(0x8045),
+ GL_RGB8(0x8051),
+ GL_RGB10_EXT(0x8052),
+ GL_RGBA4(0x8056),
+ GL_RGB5_A1(0x8057),
+ GL_RGBA8(0x8058),
+ GL_RGB10_A2_EXT(0x8059),
+ GL_TEXTURE_BINDING_2D(0x8069),
+ GL_TEXTURE_BINDING_3D(0x806A),
+ GL_TEXTURE_3D(0x806F),
+ GL_TEXTURE_WRAP_R(0x8072),
+ GL_MAX_3D_TEXTURE_SIZE(0x8073),
+ GL_VERTEX_ARRAY(0x8074),
+ GL_NORMAL_ARRAY(0x8075),
+ GL_COLOR_ARRAY(0x8076),
+ GL_TEXTURE_COORD_ARRAY(0x8078),
+ GL_VERTEX_ARRAY_SIZE(0x807A),
+ GL_VERTEX_ARRAY_TYPE(0x807B),
+ GL_VERTEX_ARRAY_STRIDE(0x807C),
+ GL_NORMAL_ARRAY_TYPE(0x807E),
+ GL_NORMAL_ARRAY_STRIDE(0x807F),
+ GL_COLOR_ARRAY_SIZE(0x8081),
+ GL_COLOR_ARRAY_TYPE(0x8082),
+ GL_COLOR_ARRAY_STRIDE(0x8083),
+ GL_TEXTURE_COORD_ARRAY_SIZE(0x8088),
+ GL_TEXTURE_COORD_ARRAY_TYPE(0x8089),
+ GL_TEXTURE_COORD_ARRAY_STRIDE(0x808A),
+ GL_VERTEX_ARRAY_POINTER(0x808E),
+ GL_NORMAL_ARRAY_POINTER(0x808F),
+ GL_COLOR_ARRAY_POINTER(0x8090),
+ GL_TEXTURE_COORD_ARRAY_POINTER(0x8092),
+ GL_MULTISAMPLE(0x809D),
+ GL_SAMPLE_ALPHA_TO_COVERAGE(0x809E),
+ GL_SAMPLE_ALPHA_TO_ONE(0x809F),
+ GL_SAMPLE_COVERAGE(0x80A0),
+ GL_SAMPLE_BUFFERS(0x80A8),
+ GL_SAMPLES(0x80A9),
+ GL_SAMPLE_COVERAGE_VALUE(0x80AA),
+ GL_SAMPLE_COVERAGE_INVERT(0x80AB),
+ GL_BLEND_DST_RGB(0x80C8),
+ GL_BLEND_SRC_RGB(0x80C9),
+ GL_BLEND_DST_ALPHA(0x80CA),
+ GL_BLEND_SRC_ALPHA(0x80CB),
+ GL_BGRA_EXT(0x80E1),
+ GL_POINT_SIZE_MIN(0x8126),
+ GL_POINT_SIZE_MAX(0x8127),
+ GL_POINT_FADE_THRESHOLD_SIZE(0x8128),
+ GL_POINT_DISTANCE_ATTENUATION(0x8129),
+ GL_CLAMP_TO_EDGE(0x812F),
+ GL_GENERATE_MIPMAP(0x8191),
+ GL_GENERATE_MIPMAP_HINT(0x8192),
+ GL_DEPTH_COMPONENT16(0x81A5),
+ GL_DEPTH_COMPONENT24(0x81A6),
+ GL_DEPTH_COMPONENT32(0x81A7),
+ GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT(0x8210),
+ GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT(0x8211),
+ GL_RG_EXT(0x8227),
+ GL_R8_EXT(0x8229),
+ GL_RG8_EXT(0x822B),
+ GL_R16F_EXT(0x822D),
+ GL_RG16F_EXT(0x822F),
+ GL_LOSE_CONTEXT_ON_RESET_EXT(0x8252),
+ GL_GUILTY_CONTEXT_RESET_EXT(0x8253),
+ GL_INNOCENT_CONTEXT_RESET_EXT(0x8254),
+ GL_UNKNOWN_CONTEXT_RESET_EXT(0x8255),
+ GL_RESET_NOTIFICATION_STRATEGY_EXT(0x8256),
+ GL_PROGRAM_SEPARABLE_EXT(0x8258),
+ GL_ACTIVE_PROGRAM_EXT(0x8259),
+ GL_PROGRAM_PIPELINE_BINDING_EXT(0x825A),
+ GL_NO_RESET_NOTIFICATION_EXT(0x8261),
+ GL_UNSIGNED_SHORT_5_6_5(0x8363),
+ GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT(0x8365),
+ GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT(0x8366),
+ GL_UNSIGNED_INT_2_10_10_10_REV_EXT(0x8368),
+ GL_MIRRORED_REPEAT(0x8370),
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT(0x83F0),
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT(0x83F1),
+ GL_ALIASED_POINT_SIZE_RANGE(0x846D),
+ GL_ALIASED_LINE_WIDTH_RANGE(0x846E),
+ GL_TEXTURE0(0x84C0),
+ GL_TEXTURE1(0x84C1),
+ GL_TEXTURE2(0x84C2),
+ GL_TEXTURE3(0x84C3),
+ GL_TEXTURE4(0x84C4),
+ GL_TEXTURE5(0x84C5),
+ GL_TEXTURE6(0x84C6),
+ GL_TEXTURE7(0x84C7),
+ GL_TEXTURE8(0x84C8),
+ GL_TEXTURE9(0x84C9),
+ GL_TEXTURE10(0x84CA),
+ GL_TEXTURE11(0x84CB),
+ GL_TEXTURE12(0x84CC),
+ GL_TEXTURE13(0x84CD),
+ GL_TEXTURE14(0x84CE),
+ GL_TEXTURE15(0x84CF),
+ GL_TEXTURE16(0x84D0),
+ GL_TEXTURE17(0x84D1),
+ GL_TEXTURE18(0x84D2),
+ GL_TEXTURE19(0x84D3),
+ GL_TEXTURE20(0x84D4),
+ GL_TEXTURE21(0x84D5),
+ GL_TEXTURE22(0x84D6),
+ GL_TEXTURE23(0x84D7),
+ GL_TEXTURE24(0x84D8),
+ GL_TEXTURE25(0x84D9),
+ GL_TEXTURE26(0x84DA),
+ GL_TEXTURE27(0x84DB),
+ GL_TEXTURE28(0x84DC),
+ GL_TEXTURE29(0x84DD),
+ GL_TEXTURE30(0x84DE),
+ GL_TEXTURE31(0x84DF),
+ GL_ACTIVE_TEXTURE(0x84E0),
+ GL_CLIENT_ACTIVE_TEXTURE(0x84E1),
+ GL_MAX_TEXTURE_UNITS(0x84E2),
+ GL_SUBTRACT(0x84E7),
+ GL_MAX_RENDERBUFFER_SIZE(0x84E8),
+ GL_ALL_COMPLETED_NV(0x84F2),
+ GL_FENCE_STATUS_NV(0x84F3),
+ GL_FENCE_CONDITION_NV(0x84F4),
+ GL_DEPTH_STENCIL(0x84F9),
+ GL_UNSIGNED_INT_24_8(0x84FA),
+ GL_MAX_TEXTURE_LOD_BIAS_EXT(0x84FD),
+ GL_TEXTURE_MAX_ANISOTROPY_EXT(0x84FE),
+ GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT(0x84FF),
+ GL_TEXTURE_FILTER_CONTROL_EXT(0x8500),
+ GL_TEXTURE_LOD_BIAS_EXT(0x8501),
+ GL_INCR_WRAP(0x8507),
+ GL_DECR_WRAP(0x8508),
+ GL_NORMAL_MAP(0x8511),
+ GL_REFLECTION_MAP(0x8512),
+ GL_TEXTURE_CUBE_MAP(0x8513),
+ GL_TEXTURE_BINDING_CUBE_MAP(0x8514),
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X(0x8515),
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X(0x8516),
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y(0x8517),
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y(0x8518),
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z(0x8519),
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z(0x851A),
+ GL_MAX_CUBE_MAP_TEXTURE_SIZE(0x851C),
+ GL_COMBINE(0x8570),
+ GL_COMBINE_RGB(0x8571),
+ GL_COMBINE_ALPHA(0x8572),
+ GL_RGB_SCALE(0x8573),
+ GL_ADD_SIGNED(0x8574),
+ GL_INTERPOLATE(0x8575),
+ GL_CONSTANT(0x8576),
+ GL_PRIMARY_COLOR(0x8577),
+ GL_PREVIOUS(0x8578),
+ GL_SRC0_RGB(0x8580),
+ GL_SRC1_RGB(0x8581),
+ GL_SRC2_RGB(0x8582),
+ GL_SRC0_ALPHA(0x8588),
+ GL_SRC1_ALPHA(0x8589),
+ GL_SRC2_ALPHA(0x858A),
+ GL_OPERAND0_RGB(0x8590),
+ GL_OPERAND1_RGB(0x8591),
+ GL_OPERAND2_RGB(0x8592),
+ GL_OPERAND0_ALPHA(0x8598),
+ GL_OPERAND1_ALPHA(0x8599),
+ GL_OPERAND2_ALPHA(0x859A),
+ GL_VERTEX_ARRAY_BINDING(0x85B5),
+ GL_UNSIGNED_SHORT_8_8_APPLE(0x85BA),
+ GL_UNSIGNED_SHORT_8_8_REV_APPLE(0x85BB),
+ GL_VERTEX_ATTRIB_ARRAY_ENABLED(0x8622),
+ GL_VERTEX_ATTRIB_ARRAY_SIZE(0x8623),
+ GL_VERTEX_ATTRIB_ARRAY_STRIDE(0x8624),
+ GL_VERTEX_ATTRIB_ARRAY_TYPE(0x8625),
+ GL_CURRENT_VERTEX_ATTRIB(0x8626),
+ GL_VERTEX_ATTRIB_ARRAY_POINTER(0x8645),
+ GL_NUM_COMPRESSED_TEXTURE_FORMATS(0x86A2),
+ GL_COMPRESSED_TEXTURE_FORMATS(0x86A3),
+ GL_MAX_VERTEX_UNITS(0x86A4),
+ GL_WEIGHT_ARRAY_TYPE(0x86A9),
+ GL_WEIGHT_ARRAY_STRIDE(0x86AA),
+ GL_WEIGHT_ARRAY_SIZE(0x86AB),
+ GL_WEIGHT_ARRAY_POINTER(0x86AC),
+ GL_WEIGHT_ARRAY(0x86AD),
+ GL_DOT3_RGB(0x86AE),
+ GL_DOT3_RGBA(0x86AF),
+ GL_Z400_BINARY_AMD(0x8740),
+ GL_PROGRAM_BINARY_LENGTH(0x8741),
+ GL_BUFFER_SIZE(0x8764),
+ GL_BUFFER_USAGE(0x8765),
+ GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD(0x87EE),
+ GL_3DC_X_AMD(0x87F9),
+ GL_3DC_XY_AMD(0x87FA),
+ GL_NUM_PROGRAM_BINARY_FORMATS(0x87FE),
+ GL_PROGRAM_BINARY_FORMATS(0x87FF),
+ GL_STENCIL_BACK_FUNC(0x8800),
+ GL_STENCIL_BACK_FAIL(0x8801),
+ GL_STENCIL_BACK_PASS_DEPTH_FAIL(0x8802),
+ GL_STENCIL_BACK_PASS_DEPTH_PASS(0x8803),
+ GL_RGBA32F_EXT(0x8814),
+ GL_RGB32F_EXT(0x8815),
+ GL_ALPHA32F_EXT(0x8816),
+ GL_LUMINANCE32F_EXT(0x8818),
+ GL_LUMINANCE_ALPHA32F_EXT(0x8819),
+ GL_RGBA16F_EXT(0x881A),
+ GL_RGB16F_EXT(0x881B),
+ GL_ALPHA16F_EXT(0x881C),
+ GL_LUMINANCE16F_EXT(0x881E),
+ GL_LUMINANCE_ALPHA16F_EXT(0x881F),
+ GL_WRITEONLY_RENDERING_QCOM(0x8823),
+ GL_MAX_DRAW_BUFFERS_NV(0x8824),
+ GL_DRAW_BUFFER0_NV(0x8825),
+ GL_DRAW_BUFFER1_NV(0x8826),
+ GL_DRAW_BUFFER2_NV(0x8827),
+ GL_DRAW_BUFFER3_NV(0x8828),
+ GL_DRAW_BUFFER4_NV(0x8829),
+ GL_DRAW_BUFFER5_NV(0x882A),
+ GL_DRAW_BUFFER6_NV(0x882B),
+ GL_DRAW_BUFFER7_NV(0x882C),
+ GL_DRAW_BUFFER8_NV(0x882D),
+ GL_DRAW_BUFFER9_NV(0x882E),
+ GL_DRAW_BUFFER10_NV(0x882F),
+ GL_DRAW_BUFFER11_NV(0x8830),
+ GL_DRAW_BUFFER12_NV(0x8831),
+ GL_DRAW_BUFFER13_NV(0x8832),
+ GL_DRAW_BUFFER14_NV(0x8833),
+ GL_DRAW_BUFFER15_NV(0x8834),
+ GL_BLEND_EQUATION_ALPHA(0x883D),
+ GL_MATRIX_PALETTE(0x8840),
+ GL_MAX_PALETTE_MATRICES(0x8842),
+ GL_CURRENT_PALETTE_MATRIX(0x8843),
+ GL_MATRIX_INDEX_ARRAY(0x8844),
+ GL_MATRIX_INDEX_ARRAY_SIZE(0x8846),
+ GL_MATRIX_INDEX_ARRAY_TYPE(0x8847),
+ GL_MATRIX_INDEX_ARRAY_STRIDE(0x8848),
+ GL_MATRIX_INDEX_ARRAY_POINTER(0x8849),
+ GL_COMPARE_REF_TO_TEXTURE_EXT(0x884E),
+ GL_CURRENT_QUERY_EXT(0x8865),
+ GL_QUERY_RESULT_EXT(0x8866),
+ GL_QUERY_RESULT_AVAILABLE_EXT(0x8867),
+ GL_POINT_SPRITE(0x8861),
+ GL_COORD_REPLACE(0x8862),
+ GL_MAX_VERTEX_ATTRIBS(0x8869),
+ GL_VERTEX_ATTRIB_ARRAY_NORMALIZED(0x886A),
+ GL_MAX_TEXTURE_IMAGE_UNITS(0x8872),
+ GL_ARRAY_BUFFER(0x8892),
+ GL_ELEMENT_ARRAY_BUFFER(0x8893),
+ GL_ARRAY_BUFFER_BINDING(0x8894),
+ GL_ELEMENT_ARRAY_BUFFER_BINDING(0x8895),
+ GL_VERTEX_ARRAY_BUFFER_BINDING(0x8896),
+ GL_NORMAL_ARRAY_BUFFER_BINDING(0x8897),
+ GL_COLOR_ARRAY_BUFFER_BINDING(0x8898),
+ GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING(0x889A),
+ GL_WEIGHT_ARRAY_BUFFER_BINDING(0x889E),
+ GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING(0x889F),
+ GL_WRITE_ONLY(0x88B9),
+ GL_BUFFER_ACCESS(0x88BB),
+ GL_BUFFER_MAPPED(0x88BC),
+ GL_BUFFER_MAP_POINTER(0x88BD),
+ GL_STREAM_DRAW(0x88E0),
+ GL_STATIC_DRAW(0x88E4),
+ GL_DYNAMIC_DRAW(0x88E8),
+ GL_DEPTH24_STENCIL8(0x88F0),
+ GL_POINT_SIZE_ARRAY_TYPE(0x898A),
+ GL_POINT_SIZE_ARRAY_STRIDE(0x898B),
+ GL_POINT_SIZE_ARRAY_POINTER(0x898C),
+ GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS(0x898D),
+ GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS(0x898E),
+ GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS(0x898F),
+ GL_RGB_422_APPLE(0x8A1F),
+ GL_PROGRAM_PIPELINE_OBJECT_EXT(0x8A4F),
+ GL_FRAGMENT_SHADER(0x8B30),
+ GL_VERTEX_SHADER(0x8B31),
+ GL_PROGRAM_OBJECT_EXT(0x8B40),
+ GL_SHADER_OBJECT_EXT(0x8B48),
+ GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS(0x8B4C),
+ GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS(0x8B4D),
+ GL_SHADER_TYPE(0x8B4F),
+ GL_FLOAT_VEC2(0x8B50),
+ GL_FLOAT_VEC3(0x8B51),
+ GL_FLOAT_VEC4(0x8B52),
+ GL_INT_VEC2(0x8B53),
+ GL_INT_VEC3(0x8B54),
+ GL_INT_VEC4(0x8B55),
+ GL_BOOL(0x8B56),
+ GL_BOOL_VEC2(0x8B57),
+ GL_BOOL_VEC3(0x8B58),
+ GL_BOOL_VEC4(0x8B59),
+ GL_FLOAT_MAT2(0x8B5A),
+ GL_FLOAT_MAT3(0x8B5B),
+ GL_FLOAT_MAT4(0x8B5C),
+ GL_SAMPLER_2D(0x8B5E),
+ GL_SAMPLER_3D(0x8B5F),
+ GL_SAMPLER_CUBE(0x8B60),
+ GL_SAMPLER_2D_SHADOW_EXT(0x8B62),
+ GL_DELETE_STATUS(0x8B80),
+ GL_COMPILE_STATUS(0x8B81),
+ GL_LINK_STATUS(0x8B82),
+ GL_VALIDATE_STATUS(0x8B83),
+ GL_INFO_LOG_LENGTH(0x8B84),
+ GL_ATTACHED_SHADERS(0x8B85),
+ GL_ACTIVE_UNIFORMS(0x8B86),
+ GL_ACTIVE_UNIFORM_MAX_LENGTH(0x8B87),
+ GL_SHADER_SOURCE_LENGTH(0x8B88),
+ GL_ACTIVE_ATTRIBUTES(0x8B89),
+ GL_ACTIVE_ATTRIBUTE_MAX_LENGTH(0x8B8A),
+ GL_FRAGMENT_SHADER_DERIVATIVE_HINT(0x8B8B),
+ GL_SHADING_LANGUAGE_VERSION(0x8B8C),
+ GL_CURRENT_PROGRAM(0x8B8D),
+ GL_PALETTE4_RGB8(0x8B90),
+ GL_PALETTE4_RGBA8(0x8B91),
+ GL_PALETTE4_R5_G6_B5(0x8B92),
+ GL_PALETTE4_RGBA4(0x8B93),
+ GL_PALETTE4_RGB5_A1(0x8B94),
+ GL_PALETTE8_RGB8(0x8B95),
+ GL_PALETTE8_RGBA8(0x8B96),
+ GL_PALETTE8_R5_G6_B5(0x8B97),
+ GL_PALETTE8_RGBA4(0x8B98),
+ GL_PALETTE8_RGB5_A1(0x8B99),
+ GL_IMPLEMENTATION_COLOR_READ_TYPE(0x8B9A),
+ GL_IMPLEMENTATION_COLOR_READ_FORMAT(0x8B9B),
+ GL_POINT_SIZE_ARRAY(0x8B9C),
+ GL_TEXTURE_CROP_RECT(0x8B9D),
+ GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING(0x8B9E),
+ GL_POINT_SIZE_ARRAY_BUFFER_BINDING(0x8B9F),
+ GL_COUNTER_TYPE_AMD(0x8BC0),
+ GL_COUNTER_RANGE_AMD(0x8BC1),
+ GL_UNSIGNED_INT64_AMD(0x8BC2),
+ GL_PERCENTAGE_AMD(0x8BC3),
+ GL_PERFMON_RESULT_AVAILABLE_AMD(0x8BC4),
+ GL_PERFMON_RESULT_SIZE_AMD(0x8BC5),
+ GL_PERFMON_RESULT_AMD(0x8BC6),
+ GL_TEXTURE_WIDTH_QCOM(0x8BD2),
+ GL_TEXTURE_HEIGHT_QCOM(0x8BD3),
+ GL_TEXTURE_DEPTH_QCOM(0x8BD4),
+ GL_TEXTURE_INTERNAL_FORMAT_QCOM(0x8BD5),
+ GL_TEXTURE_FORMAT_QCOM(0x8BD6),
+ GL_TEXTURE_TYPE_QCOM(0x8BD7),
+ GL_TEXTURE_IMAGE_VALID_QCOM(0x8BD8),
+ GL_TEXTURE_NUM_LEVELS_QCOM(0x8BD9),
+ GL_TEXTURE_TARGET_QCOM(0x8BDA),
+ GL_TEXTURE_OBJECT_VALID_QCOM(0x8BDB),
+ GL_STATE_RESTORE(0x8BDC),
+ GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG(0x8C00),
+ GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG(0x8C01),
+ GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG(0x8C02),
+ GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG(0x8C03),
+ GL_MODULATE_COLOR_IMG(0x8C04),
+ GL_RECIP_ADD_SIGNED_ALPHA_IMG(0x8C05),
+ GL_TEXTURE_ALPHA_MODULATE_IMG(0x8C06),
+ GL_FACTOR_ALPHA_MODULATE_IMG(0x8C07),
+ GL_FRAGMENT_ALPHA_MODULATE_IMG(0x8C08),
+ GL_ADD_BLEND_IMG(0x8C09),
+ GL_SGX_BINARY_IMG(0x8C0A),
+ GL_UNSIGNED_NORMALIZED_EXT(0x8C17),
+ GL_ANY_SAMPLES_PASSED_EXT(0x8C2F),
+ GL_SRGB_EXT(0x8C40),
+ GL_SRGB_ALPHA_EXT(0x8C42),
+ GL_SRGB8_ALPHA8_EXT(0x8C43),
+ GL_ATC_RGB_AMD(0x8C92),
+ GL_ATC_RGBA_EXPLICIT_ALPHA_AMD(0x8C93),
+ GL_STENCIL_BACK_REF(0x8CA3),
+ GL_STENCIL_BACK_VALUE_MASK(0x8CA4),
+ GL_STENCIL_BACK_WRITEMASK(0x8CA5),
+ GL_FRAMEBUFFER_BINDING(0x8CA6),
+ GL_RENDERBUFFER_BINDING(0x8CA7),
+ GL_READ_FRAMEBUFFER_APPLE(0x8CA8),
+ GL_DRAW_FRAMEBUFFER_APPLE(0x8CA9),
+ GL_READ_FRAMEBUFFER_BINDING_APPLE(0x8CAA),
+ GL_RENDERBUFFER_SAMPLES_APPLE(0x8CAB),
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE(0x8CD0),
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME(0x8CD1),
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL(0x8CD2),
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE(0x8CD3),
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET(0x8CD4),
+ GL_FRAMEBUFFER_COMPLETE(0x8CD5),
+ GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT(0x8CD6),
+ GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT(0x8CD7),
+ GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS(0x8CD9),
+ GL_FRAMEBUFFER_INCOMPLETE_FORMATS(0x8CDA),
+ GL_FRAMEBUFFER_UNSUPPORTED(0x8CDD),
+ GL_MAX_COLOR_ATTACHMENTS_NV(0x8CDF),
+ GL_COLOR_ATTACHMENT0(0x8CE0),
+ GL_COLOR_ATTACHMENT1_NV(0x8CE1),
+ GL_COLOR_ATTACHMENT2_NV(0x8CE2),
+ GL_COLOR_ATTACHMENT3_NV(0x8CE3),
+ GL_COLOR_ATTACHMENT4_NV(0x8CE4),
+ GL_COLOR_ATTACHMENT5_NV(0x8CE5),
+ GL_COLOR_ATTACHMENT6_NV(0x8CE6),
+ GL_COLOR_ATTACHMENT7_NV(0x8CE7),
+ GL_COLOR_ATTACHMENT8_NV(0x8CE8),
+ GL_COLOR_ATTACHMENT9_NV(0x8CE9),
+ GL_COLOR_ATTACHMENT10_NV(0x8CEA),
+ GL_COLOR_ATTACHMENT11_NV(0x8CEB),
+ GL_COLOR_ATTACHMENT12_NV(0x8CEC),
+ GL_COLOR_ATTACHMENT13_NV(0x8CED),
+ GL_COLOR_ATTACHMENT14_NV(0x8CEE),
+ GL_COLOR_ATTACHMENT15_NV(0x8CEF),
+ GL_DEPTH_ATTACHMENT(0x8D00),
+ GL_STENCIL_ATTACHMENT(0x8D20),
+ GL_FRAMEBUFFER(0x8D40),
+ GL_RENDERBUFFER(0x8D41),
+ GL_RENDERBUFFER_WIDTH(0x8D42),
+ GL_RENDERBUFFER_HEIGHT(0x8D43),
+ GL_RENDERBUFFER_INTERNAL_FORMAT(0x8D44),
+ GL_STENCIL_INDEX1(0x8D46),
+ GL_STENCIL_INDEX4(0x8D47),
+ GL_STENCIL_INDEX8(0x8D48),
+ GL_RENDERBUFFER_RED_SIZE(0x8D50),
+ GL_RENDERBUFFER_GREEN_SIZE(0x8D51),
+ GL_RENDERBUFFER_BLUE_SIZE(0x8D52),
+ GL_RENDERBUFFER_ALPHA_SIZE(0x8D53),
+ GL_RENDERBUFFER_DEPTH_SIZE(0x8D54),
+ GL_RENDERBUFFER_STENCIL_SIZE(0x8D55),
+ GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE(0x8D56),
+ GL_MAX_SAMPLES_APPLE(0x8D57),
+ GL_TEXTURE_GEN_STR(0x8D60),
+ GL_HALF_FLOAT(0x8D61),
+ GL_RGB565(0x8D62),
+ GL_ETC1_RGB8(0x8D64),
+ GL_TEXTURE_EXTERNAL(0x8D65),
+ GL_SAMPLER_EXTERNAL(0x8D66),
+ GL_TEXTURE_BINDING_EXTERNAL(0x8D67),
+ GL_REQUIRED_TEXTURE_IMAGE_UNITS(0x8D68),
+ GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT(0x8D6A),
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT(0x8D6C),
+ GL_LOW_FLOAT(0x8DF0),
+ GL_MEDIUM_FLOAT(0x8DF1),
+ GL_HIGH_FLOAT(0x8DF2),
+ GL_LOW_INT(0x8DF3),
+ GL_MEDIUM_INT(0x8DF4),
+ GL_HIGH_INT(0x8DF5),
+ GL_UNSIGNED_INT_10_10_10_2(0x8DF6),
+ GL_INT_10_10_10_2(0x8DF7),
+ GL_SHADER_BINARY_FORMATS(0x8DF8),
+ GL_NUM_SHADER_BINARY_FORMATS(0x8DF9),
+ GL_SHADER_COMPILER(0x8DFA),
+ GL_MAX_VERTEX_UNIFORM_VECTORS(0x8DFB),
+ GL_MAX_VARYING_VECTORS(0x8DFC),
+ GL_MAX_FRAGMENT_UNIFORM_VECTORS(0x8DFD),
+ GL_DEPTH_COMPONENT16_NONLINEAR_NV(0x8E2C),
+ GL_COVERAGE_COMPONENT_NV(0x8ED0),
+ GL_COVERAGE_COMPONENT4_NV(0x8ED1),
+ GL_COVERAGE_ATTACHMENT_NV(0x8ED2),
+ GL_COVERAGE_BUFFERS_NV(0x8ED3),
+ GL_COVERAGE_SAMPLES_NV(0x8ED4),
+ GL_COVERAGE_ALL_FRAGMENTS_NV(0x8ED5),
+ GL_COVERAGE_EDGE_FRAGMENTS_NV(0x8ED6),
+ GL_COVERAGE_AUTOMATIC_NV(0x8ED7),
+ GL_MALI_SHADER_BINARY_ARM(0x8F60),
+ GL_PERFMON_GLOBAL_MODE_QCOM(0x8FA0),
+ GL_SHADER_BINARY_VIV(0x8FC4),
+ GL_CONTEXT_ROBUST_ACCESS_EXT(0x90F3),
+ GL_TEXTURE_IMMUTABLE_FORMAT_EXT(0x912F),
+ GL_SGX_PROGRAM_BINARY_IMG(0x9130),
+ GL_RENDERBUFFER_SAMPLES_EXT(0x9133),
+ GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT(0x9134),
+ GL_MAX_SAMPLES_EXT(0x9135),
+ GL_TEXTURE_SAMPLES_IMG(0x9136),
+ GL_BUFFER_OBJECT_EXT(0x9151),
+ GL_QUERY_OBJECT_EXT(0x9153),
+ GL_VERTEX_ARRAY_OBJECT_EXT(0x9154),
+ GL_SHADER_BINARY_DMP(0x9250),
+ GL_BGRA8_EXT(0x93A1),
+
+ // Constants defined by ES3
+ GL_READ_BUFFER(0x0C02),
+ GL_PACK_ROW_LENGTH(0x0D02),
+ GL_PACK_SKIP_ROWS(0x0D03),
+ GL_PACK_SKIP_PIXELS(0x0D04),
+ GL_COLOR(0x1800),
+ GL_DEPTH(0x1801),
+ GL_STENCIL(0x1802),
+ GL_RED(0x1903),
+ GL_RGB10_A2(0x8059),
+ GL_UNPACK_SKIP_IMAGES(0x806D),
+ GL_UNPACK_IMAGE_HEIGHT(0x806E),
+ GL_UNSIGNED_INT_2_10_10_10_REV(0x8368),
+ GL_MAX_ELEMENTS_VERTICES(0x80E8),
+ GL_MAX_ELEMENTS_INDICES(0x80E9),
+ GL_TEXTURE_MIN_LOD(0x813A),
+ GL_TEXTURE_MAX_LOD(0x813B),
+ GL_TEXTURE_BASE_LEVEL(0x813C),
+ GL_TEXTURE_MAX_LEVEL(0x813D),
+ GL_MIN(0x8007),
+ GL_MAX(0x8008),
+ GL_MAX_TEXTURE_LOD_BIAS(0x84FD),
+ GL_TEXTURE_COMPARE_MODE(0x884C),
+ GL_TEXTURE_COMPARE_FUNC(0x884D),
+ GL_CURRENT_QUERY(0x8865),
+ GL_QUERY_RESULT(0x8866),
+ GL_QUERY_RESULT_AVAILABLE(0x8867),
+ GL_STREAM_READ(0x88E1),
+ GL_STREAM_COPY(0x88E2),
+ GL_STATIC_READ(0x88E5),
+ GL_STATIC_COPY(0x88E6),
+ GL_DYNAMIC_READ(0x88E9),
+ GL_DYNAMIC_COPY(0x88EA),
+ GL_MAX_DRAW_BUFFERS(0x8824),
+ GL_DRAW_BUFFER0(0x8825),
+ GL_DRAW_BUFFER1(0x8826),
+ GL_DRAW_BUFFER2(0x8827),
+ GL_DRAW_BUFFER3(0x8828),
+ GL_DRAW_BUFFER4(0x8829),
+ GL_DRAW_BUFFER5(0x882A),
+ GL_DRAW_BUFFER6(0x882B),
+ GL_DRAW_BUFFER7(0x882C),
+ GL_DRAW_BUFFER8(0x882D),
+ GL_DRAW_BUFFER9(0x882E),
+ GL_DRAW_BUFFER10(0x882F),
+ GL_DRAW_BUFFER11(0x8830),
+ GL_DRAW_BUFFER12(0x8831),
+ GL_DRAW_BUFFER13(0x8832),
+ GL_DRAW_BUFFER14(0x8833),
+ GL_DRAW_BUFFER15(0x8834),
+ GL_MAX_FRAGMENT_UNIFORM_COMPONENTS(0x8B49),
+ GL_MAX_VERTEX_UNIFORM_COMPONENTS(0x8B4A),
+ GL_SAMPLER_2D_SHADOW(0x8B62),
+ GL_PIXEL_PACK_BUFFER(0x88EB),
+ GL_PIXEL_UNPACK_BUFFER(0x88EC),
+ GL_PIXEL_PACK_BUFFER_BINDING(0x88ED),
+ GL_PIXEL_UNPACK_BUFFER_BINDING(0x88EF),
+ GL_FLOAT_MAT2x3(0x8B65),
+ GL_FLOAT_MAT2x4(0x8B66),
+ GL_FLOAT_MAT3x2(0x8B67),
+ GL_FLOAT_MAT3x4(0x8B68),
+ GL_FLOAT_MAT4x2(0x8B69),
+ GL_FLOAT_MAT4x3(0x8B6A),
+ GL_SRGB(0x8C40),
+ GL_SRGB8(0x8C41),
+ GL_SRGB8_ALPHA8(0x8C43),
+ GL_COMPARE_REF_TO_TEXTURE(0x884E),
+ GL_MAJOR_VERSION(0x821B),
+ GL_MINOR_VERSION(0x821C),
+ GL_NUM_EXTENSIONS(0x821D),
+ GL_RGBA32F(0x8814),
+ GL_RGB32F(0x8815),
+ GL_RGBA16F(0x881A),
+ GL_RGB16F(0x881B),
+ GL_VERTEX_ATTRIB_ARRAY_INTEGER(0x88FD),
+ GL_MAX_ARRAY_TEXTURE_LAYERS(0x88FF),
+ GL_MIN_PROGRAM_TEXEL_OFFSET(0x8904),
+ GL_MAX_PROGRAM_TEXEL_OFFSET(0x8905),
+ GL_MAX_VARYING_COMPONENTS(0x8B4B),
+ GL_TEXTURE_2D_ARRAY(0x8C1A),
+ GL_TEXTURE_BINDING_2D_ARRAY(0x8C1D),
+ GL_R11F_G11F_B10F(0x8C3A),
+ GL_UNSIGNED_INT_10F_11F_11F_REV(0x8C3B),
+ GL_RGB9_E5(0x8C3D),
+ GL_UNSIGNED_INT_5_9_9_9_REV(0x8C3E),
+ GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH(0x8C76),
+ GL_TRANSFORM_FEEDBACK_BUFFER_MODE(0x8C7F),
+ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS(0x8C80),
+ GL_TRANSFORM_FEEDBACK_VARYINGS(0x8C83),
+ GL_TRANSFORM_FEEDBACK_BUFFER_START(0x8C84),
+ GL_TRANSFORM_FEEDBACK_BUFFER_SIZE(0x8C85),
+ GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN(0x8C88),
+ GL_RASTERIZER_DISCARD(0x8C89),
+ GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS(0x8C8A),
+ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS(0x8C8B),
+ GL_INTERLEAVED_ATTRIBS(0x8C8C),
+ GL_SEPARATE_ATTRIBS(0x8C8D),
+ GL_TRANSFORM_FEEDBACK_BUFFER(0x8C8E),
+ GL_TRANSFORM_FEEDBACK_BUFFER_BINDING(0x8C8F),
+ GL_RGBA32UI(0x8D70),
+ GL_RGB32UI(0x8D71),
+ GL_RGBA16UI(0x8D76),
+ GL_RGB16UI(0x8D77),
+ GL_RGBA8UI(0x8D7C),
+ GL_RGB8UI(0x8D7D),
+ GL_RGBA32I(0x8D82),
+ GL_RGB32I(0x8D83),
+ GL_RGBA16I(0x8D88),
+ GL_RGB16I(0x8D89),
+ GL_RGBA8I(0x8D8E),
+ GL_RGB8I(0x8D8F),
+ GL_RED_INTEGER(0x8D94),
+ GL_RGB_INTEGER(0x8D98),
+ GL_RGBA_INTEGER(0x8D99),
+ GL_SAMPLER_2D_ARRAY(0x8DC1),
+ GL_SAMPLER_2D_ARRAY_SHADOW(0x8DC4),
+ GL_SAMPLER_CUBE_SHADOW(0x8DC5),
+ GL_UNSIGNED_INT_VEC2(0x8DC6),
+ GL_UNSIGNED_INT_VEC3(0x8DC7),
+ GL_UNSIGNED_INT_VEC4(0x8DC8),
+ GL_INT_SAMPLER_2D(0x8DCA),
+ GL_INT_SAMPLER_3D(0x8DCB),
+ GL_INT_SAMPLER_CUBE(0x8DCC),
+ GL_INT_SAMPLER_2D_ARRAY(0x8DCF),
+ GL_UNSIGNED_INT_SAMPLER_2D(0x8DD2),
+ GL_UNSIGNED_INT_SAMPLER_3D(0x8DD3),
+ GL_UNSIGNED_INT_SAMPLER_CUBE(0x8DD4),
+ GL_UNSIGNED_INT_SAMPLER_2D_ARRAY(0x8DD7),
+ GL_BUFFER_ACCESS_FLAGS(0x911F),
+ GL_BUFFER_MAP_LENGTH(0x9120),
+ GL_BUFFER_MAP_OFFSET(0x9121),
+ GL_DEPTH_COMPONENT32F(0x8CAC),
+ GL_DEPTH32F_STENCIL8(0x8CAD),
+ GL_FLOAT_32_UNSIGNED_INT_24_8_REV(0x8DAD),
+ GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING(0x8210),
+ GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE(0x8211),
+ GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE(0x8212),
+ GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE(0x8213),
+ GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE(0x8214),
+ GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE(0x8215),
+ GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE(0x8216),
+ GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE(0x8217),
+ GL_FRAMEBUFFER_DEFAULT(0x8218),
+ GL_FRAMEBUFFER_UNDEFINED(0x8219),
+ GL_DEPTH_STENCIL_ATTACHMENT(0x821A),
+ GL_UNSIGNED_NORMALIZED(0x8C17),
+ GL_READ_FRAMEBUFFER(0x8CA8),
+ GL_DRAW_FRAMEBUFFER(0x8CA9),
+ GL_READ_FRAMEBUFFER_BINDING(0x8CAA),
+ GL_RENDERBUFFER_SAMPLES(0x8CAB),
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER(0x8CD4),
+ GL_MAX_COLOR_ATTACHMENTS(0x8CDF),
+ GL_COLOR_ATTACHMENT1(0x8CE1),
+ GL_COLOR_ATTACHMENT2(0x8CE2),
+ GL_COLOR_ATTACHMENT3(0x8CE3),
+ GL_COLOR_ATTACHMENT4(0x8CE4),
+ GL_COLOR_ATTACHMENT5(0x8CE5),
+ GL_COLOR_ATTACHMENT6(0x8CE6),
+ GL_COLOR_ATTACHMENT7(0x8CE7),
+ GL_COLOR_ATTACHMENT8(0x8CE8),
+ GL_COLOR_ATTACHMENT9(0x8CE9),
+ GL_COLOR_ATTACHMENT10(0x8CEA),
+ GL_COLOR_ATTACHMENT11(0x8CEB),
+ GL_COLOR_ATTACHMENT12(0x8CEC),
+ GL_COLOR_ATTACHMENT13(0x8CED),
+ GL_COLOR_ATTACHMENT14(0x8CEE),
+ GL_COLOR_ATTACHMENT15(0x8CEF),
+ GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE(0x8D56),
+ GL_MAX_SAMPLES(0x8D57),
+ GL_MAP_READ_BIT(0x0001),
+ GL_MAP_WRITE_BIT(0x0002),
+ GL_MAP_INVALIDATE_RANGE_BIT(0x0004),
+ GL_MAP_INVALIDATE_BUFFER_BIT(0x0008),
+ GL_MAP_FLUSH_EXPLICIT_BIT(0x0010),
+ GL_MAP_UNSYNCHRONIZED_BIT(0x0020),
+ GL_RG(0x8227),
+ GL_RG_INTEGER(0x8228),
+ GL_R8(0x8229),
+ GL_RG8(0x822B),
+ GL_R16F(0x822D),
+ GL_R32F(0x822E),
+ GL_RG16F(0x822F),
+ GL_RG32F(0x8230),
+ GL_R8I(0x8231),
+ GL_R8UI(0x8232),
+ GL_R16I(0x8233),
+ GL_R16UI(0x8234),
+ GL_R32I(0x8235),
+ GL_R32UI(0x8236),
+ GL_RG8I(0x8237),
+ GL_RG8UI(0x8238),
+ GL_RG16I(0x8239),
+ GL_RG16UI(0x823A),
+ GL_RG32I(0x823B),
+ GL_RG32UI(0x823C),
+ GL_R8_SNORM(0x8F94),
+ GL_RG8_SNORM(0x8F95),
+ GL_RGB8_SNORM(0x8F96),
+ GL_RGBA8_SNORM(0x8F97),
+ GL_SIGNED_NORMALIZED(0x8F9C),
+ GL_PRIMITIVE_RESTART_FIXED_INDEX(0x8D69),
+ GL_COPY_READ_BUFFER(0x8F36),
+ GL_COPY_WRITE_BUFFER(0x8F37),
+ GL_UNIFORM_BUFFER(0x8A11),
+ GL_UNIFORM_BUFFER_BINDING(0x8A28),
+ GL_UNIFORM_BUFFER_START(0x8A29),
+ GL_UNIFORM_BUFFER_SIZE(0x8A2A),
+ GL_MAX_VERTEX_UNIFORM_BLOCKS(0x8A2B),
+ GL_MAX_FRAGMENT_UNIFORM_BLOCKS(0x8A2D),
+ GL_MAX_COMBINED_UNIFORM_BLOCKS(0x8A2E),
+ GL_MAX_UNIFORM_BUFFER_BINDINGS(0x8A2F),
+ GL_MAX_UNIFORM_BLOCK_SIZE(0x8A30),
+ GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS(0x8A31),
+ GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS(0x8A33),
+ GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT(0x8A34),
+ GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH(0x8A35),
+ GL_ACTIVE_UNIFORM_BLOCKS(0x8A36),
+ GL_UNIFORM_TYPE(0x8A37),
+ GL_UNIFORM_SIZE(0x8A38),
+ GL_UNIFORM_NAME_LENGTH(0x8A39),
+ GL_UNIFORM_BLOCK_INDEX(0x8A3A),
+ GL_UNIFORM_OFFSET(0x8A3B),
+ GL_UNIFORM_ARRAY_STRIDE(0x8A3C),
+ GL_UNIFORM_MATRIX_STRIDE(0x8A3D),
+ GL_UNIFORM_IS_ROW_MAJOR(0x8A3E),
+ GL_UNIFORM_BLOCK_BINDING(0x8A3F),
+ GL_UNIFORM_BLOCK_DATA_SIZE(0x8A40),
+ GL_UNIFORM_BLOCK_NAME_LENGTH(0x8A41),
+ GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS(0x8A42),
+ GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES(0x8A43),
+ GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER(0x8A44),
+ GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER(0x8A46),
+ GL_MAX_VERTEX_OUTPUT_COMPONENTS(0x9122),
+ GL_MAX_FRAGMENT_INPUT_COMPONENTS(0x9125),
+ GL_MAX_SERVER_WAIT_TIMEOUT(0x9111),
+ GL_OBJECT_TYPE(0x9112),
+ GL_SYNC_CONDITION(0x9113),
+ GL_SYNC_STATUS(0x9114),
+ GL_SYNC_FLAGS(0x9115),
+ GL_SYNC_FENCE(0x9116),
+ GL_SYNC_GPU_COMMANDS_COMPLETE(0x9117),
+ GL_UNSIGNALED(0x9118),
+ GL_SIGNALED(0x9119),
+ GL_ALREADY_SIGNALED(0x911A),
+ GL_TIMEOUT_EXPIRED(0x911B),
+ GL_CONDITION_SATISFIED(0x911C),
+ GL_WAIT_FAILED(0x911D),
+ GL_SYNC_FLUSH_COMMANDS_BIT(0x00000001),
+ GL_TIMEOUT_IGNORED(0xFFFFFFFFFFFFFFFFl),
+ GL_VERTEX_ATTRIB_ARRAY_DIVISOR(0x88FE),
+ GL_ANY_SAMPLES_PASSED(0x8C2F),
+ GL_ANY_SAMPLES_PASSED_CONSERVATIVE(0x8D6A),
+ GL_SAMPLER_BINDING(0x8919),
+ GL_RGB10_A2UI(0x906F),
+ GL_TEXTURE_SWIZZLE_R(0x8E42),
+ GL_TEXTURE_SWIZZLE_G(0x8E43),
+ GL_TEXTURE_SWIZZLE_B(0x8E44),
+ GL_TEXTURE_SWIZZLE_A(0x8E45),
+ GL_GREEN(0x1904),
+ GL_BLUE(0x1905),
+ GL_INT_2_10_10_10_REV(0x8D9F),
+ GL_TRANSFORM_FEEDBACK(0x8E22),
+ GL_TRANSFORM_FEEDBACK_PAUSED(0x8E23),
+ GL_TRANSFORM_FEEDBACK_ACTIVE(0x8E24),
+ GL_TRANSFORM_FEEDBACK_BINDING(0x8E25),
+ GL_PROGRAM_BINARY_RETRIEVABLE_HINT(0x8257),
+ GL_COMPRESSED_R11_EAC(0x9270),
+ GL_COMPRESSED_SIGNED_R11_EAC(0x9271),
+ GL_COMPRESSED_RG11_EAC(0x9272),
+ GL_COMPRESSED_SIGNED_RG11_EAC(0x9273),
+ GL_COMPRESSED_RGB8_ETC2(0x9274),
+ GL_COMPRESSED_SRGB8_ETC2(0x9275),
+ GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2(0x9276),
+ GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2(0x9277),
+ GL_COMPRESSED_RGBA8_ETC2_EAC(0x9278),
+ GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC(0x9279),
+ GL_TEXTURE_IMMUTABLE_FORMAT(0x912F),
+ GL_MAX_ELEMENT_INDEX(0x8D6B),
+ GL_NUM_SAMPLE_COUNTS(0x9380),
+ GL_TEXTURE_IMMUTABLE_LEVELS(0x82DF),
+
+ GL_ALL_SHADER_BITS_EXT(0xFFFFFFFF),
+ ;
+
+ public final long value;
+ GLEnum(final long value) {
+ this.value = value;
+ }
+
+ private static final java.util.HashMap<Long, GLEnum> reverseMap = new java.util.HashMap<Long, GLEnum>();
+ static {
+ for (GLEnum e : GLEnum.values())
+ reverseMap.put(e.value, e);
+ }
+
+ public static GLEnum valueOf(final long value) {
+ return reverseMap.get(value);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLProtoBuf.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLProtoBuf.java
new file mode 100644
index 000000000..3c0fbd49e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLProtoBuf.java
@@ -0,0 +1,3119 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: gltrace.proto
+
+package com.android.ide.eclipse.gltrace;
+
+public final class GLProtoBuf {
+ private GLProtoBuf() {}
+ public static void registerAllExtensions(
+ com.google.protobuf.ExtensionRegistryLite registry) {
+ }
+ public static final class GLMessage extends
+ com.google.protobuf.GeneratedMessageLite {
+ // Use GLMessage.newBuilder() to construct.
+ private GLMessage() {
+ initFields();
+ }
+ private GLMessage(boolean noInit) {}
+
+ private static final GLMessage defaultInstance;
+ public static GLMessage getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ @Override
+ public GLMessage getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public enum Function
+ implements com.google.protobuf.Internal.EnumLite {
+ glActiveTexture(0, 0),
+ glAlphaFunc(1, 1),
+ glAlphaFuncx(2, 2),
+ glAlphaFuncxOES(3, 3),
+ glAttachShader(4, 4),
+ glBeginPerfMonitorAMD(5, 5),
+ glBindAttribLocation(6, 6),
+ glBindBuffer(7, 7),
+ glBindFramebuffer(8, 8),
+ glBindFramebufferOES(9, 9),
+ glBindRenderbuffer(10, 10),
+ glBindRenderbufferOES(11, 11),
+ glBindTexture(12, 12),
+ glBindVertexArrayOES(13, 13),
+ glBlendColor(14, 14),
+ glBlendEquation(15, 15),
+ glBlendEquationOES(16, 16),
+ glBlendEquationSeparate(17, 17),
+ glBlendEquationSeparateOES(18, 18),
+ glBlendFunc(19, 19),
+ glBlendFuncSeparate(20, 20),
+ glBlendFuncSeparateOES(21, 21),
+ glBufferData(22, 22),
+ glBufferSubData(23, 23),
+ glCheckFramebufferStatus(24, 24),
+ glCheckFramebufferStatusOES(25, 25),
+ glClearColor(26, 26),
+ glClearColorx(27, 27),
+ glClearColorxOES(28, 28),
+ glClearDepthf(29, 29),
+ glClearDepthfOES(30, 30),
+ glClearDepthx(31, 31),
+ glClearDepthxOES(32, 32),
+ glClear(33, 33),
+ glClearStencil(34, 34),
+ glClientActiveTexture(35, 35),
+ glClipPlanef(36, 36),
+ glClipPlanefIMG(37, 37),
+ glClipPlanefOES(38, 38),
+ glClipPlanex(39, 39),
+ glClipPlanexIMG(40, 40),
+ glClipPlanexOES(41, 41),
+ glColor4f(42, 42),
+ glColor4ub(43, 43),
+ glColor4x(44, 44),
+ glColor4xOES(45, 45),
+ glColorMask(46, 46),
+ glColorPointer(47, 47),
+ glCompileShader(48, 48),
+ glCompressedTexImage2D(49, 49),
+ glCompressedTexImage3DOES(50, 50),
+ glCompressedTexSubImage2D(51, 51),
+ glCompressedTexSubImage3DOES(52, 52),
+ glCopyTexImage2D(53, 53),
+ glCopyTexSubImage2D(54, 54),
+ glCopyTexSubImage3DOES(55, 55),
+ glCoverageMaskNV(56, 56),
+ glCoverageOperationNV(57, 57),
+ glCreateProgram(58, 58),
+ glCreateShader(59, 59),
+ glCullFace(60, 60),
+ glCurrentPaletteMatrixOES(61, 61),
+ glDeleteBuffers(62, 62),
+ glDeleteFencesNV(63, 63),
+ glDeleteFramebuffers(64, 64),
+ glDeleteFramebuffersOES(65, 65),
+ glDeletePerfMonitorsAMD(66, 66),
+ glDeleteProgram(67, 67),
+ glDeleteRenderbuffers(68, 68),
+ glDeleteRenderbuffersOES(69, 69),
+ glDeleteShader(70, 70),
+ glDeleteTextures(71, 71),
+ glDeleteVertexArraysOES(72, 72),
+ glDepthFunc(73, 73),
+ glDepthMask(74, 74),
+ glDepthRangef(75, 75),
+ glDepthRangefOES(76, 76),
+ glDepthRangex(77, 77),
+ glDepthRangexOES(78, 78),
+ glDetachShader(79, 79),
+ glDisableClientState(80, 80),
+ glDisableDriverControlQCOM(81, 81),
+ glDisable(82, 82),
+ glDisableVertexAttribArray(83, 83),
+ glDiscardFramebufferEXT(84, 84),
+ glDrawArrays(85, 85),
+ glDrawElements(86, 86),
+ glDrawTexfOES(87, 87),
+ glDrawTexfvOES(88, 88),
+ glDrawTexiOES(89, 89),
+ glDrawTexivOES(90, 90),
+ glDrawTexsOES(91, 91),
+ glDrawTexsvOES(92, 92),
+ glDrawTexxOES(93, 93),
+ glDrawTexxvOES(94, 94),
+ glEGLImageTargetRenderbufferStorageOES(95, 95),
+ glEGLImageTargetTexture2DOES(96, 96),
+ glEnableClientState(97, 97),
+ glEnableDriverControlQCOM(98, 98),
+ glEnable(99, 99),
+ glEnableVertexAttribArray(100, 100),
+ glEndPerfMonitorAMD(101, 101),
+ glEndTilingQCOM(102, 102),
+ glExtGetBufferPointervQCOM(103, 103),
+ glExtGetBuffersQCOM(104, 104),
+ glExtGetFramebuffersQCOM(105, 105),
+ glExtGetProgramBinarySourceQCOM(106, 106),
+ glExtGetProgramsQCOM(107, 107),
+ glExtGetRenderbuffersQCOM(108, 108),
+ glExtGetShadersQCOM(109, 109),
+ glExtGetTexLevelParameterivQCOM(110, 110),
+ glExtGetTexSubImageQCOM(111, 111),
+ glExtGetTexturesQCOM(112, 112),
+ glExtIsProgramBinaryQCOM(113, 113),
+ glExtTexObjectStateOverrideiQCOM(114, 114),
+ glFinishFenceNV(115, 115),
+ glFinish(116, 116),
+ glFlush(117, 117),
+ glFogf(118, 118),
+ glFogfv(119, 119),
+ glFogx(120, 120),
+ glFogxOES(121, 121),
+ glFogxv(122, 122),
+ glFogxvOES(123, 123),
+ glFramebufferRenderbuffer(124, 124),
+ glFramebufferRenderbufferOES(125, 125),
+ glFramebufferTexture2D(126, 126),
+ glFramebufferTexture2DMultisampleIMG(127, 127),
+ glFramebufferTexture2DOES(128, 128),
+ glFramebufferTexture3DOES(129, 129),
+ glFrontFace(130, 130),
+ glFrustumf(131, 131),
+ glFrustumfOES(132, 132),
+ glFrustumx(133, 133),
+ glFrustumxOES(134, 134),
+ glGenBuffers(135, 135),
+ glGenerateMipmap(136, 136),
+ glGenerateMipmapOES(137, 137),
+ glGenFencesNV(138, 138),
+ glGenFramebuffers(139, 139),
+ glGenFramebuffersOES(140, 140),
+ glGenPerfMonitorsAMD(141, 141),
+ glGenRenderbuffers(142, 142),
+ glGenRenderbuffersOES(143, 143),
+ glGenTextures(144, 144),
+ glGenVertexArraysOES(145, 145),
+ glGetActiveAttrib(146, 146),
+ glGetActiveUniform(147, 147),
+ glGetAttachedShaders(148, 148),
+ glGetAttribLocation(149, 149),
+ glGetBooleanv(150, 150),
+ glGetBufferParameteriv(151, 151),
+ glGetBufferPointervOES(152, 152),
+ glGetClipPlanef(153, 153),
+ glGetClipPlanefOES(154, 154),
+ glGetClipPlanex(155, 155),
+ glGetClipPlanexOES(156, 156),
+ glGetDriverControlsQCOM(157, 157),
+ glGetDriverControlStringQCOM(158, 158),
+ glGetError(159, 159),
+ glGetFenceivNV(160, 160),
+ glGetFixedv(161, 161),
+ glGetFixedvOES(162, 162),
+ glGetFloatv(163, 163),
+ glGetFramebufferAttachmentParameteriv(164, 164),
+ glGetFramebufferAttachmentParameterivOES(165, 165),
+ glGetIntegerv(166, 166),
+ glGetLightfv(167, 167),
+ glGetLightxv(168, 168),
+ glGetLightxvOES(169, 169),
+ glGetMaterialfv(170, 170),
+ glGetMaterialxv(171, 171),
+ glGetMaterialxvOES(172, 172),
+ glGetPerfMonitorCounterDataAMD(173, 173),
+ glGetPerfMonitorCounterInfoAMD(174, 174),
+ glGetPerfMonitorCountersAMD(175, 175),
+ glGetPerfMonitorCounterStringAMD(176, 176),
+ glGetPerfMonitorGroupsAMD(177, 177),
+ glGetPerfMonitorGroupStringAMD(178, 178),
+ glGetPointerv(179, 179),
+ glGetProgramBinaryOES(180, 180),
+ glGetProgramInfoLog(181, 181),
+ glGetProgramiv(182, 182),
+ glGetRenderbufferParameteriv(183, 183),
+ glGetRenderbufferParameterivOES(184, 184),
+ glGetShaderInfoLog(185, 185),
+ glGetShaderiv(186, 186),
+ glGetShaderPrecisionFormat(187, 187),
+ glGetShaderSource(188, 188),
+ glGetString(189, 189),
+ glGetTexEnvfv(190, 190),
+ glGetTexEnviv(191, 191),
+ glGetTexEnvxv(192, 192),
+ glGetTexEnvxvOES(193, 193),
+ glGetTexGenfvOES(194, 194),
+ glGetTexGenivOES(195, 195),
+ glGetTexGenxvOES(196, 196),
+ glGetTexParameterfv(197, 197),
+ glGetTexParameteriv(198, 198),
+ glGetTexParameterxv(199, 199),
+ glGetTexParameterxvOES(200, 200),
+ glGetUniformfv(201, 201),
+ glGetUniformiv(202, 202),
+ glGetUniformLocation(203, 203),
+ glGetVertexAttribfv(204, 204),
+ glGetVertexAttribiv(205, 205),
+ glGetVertexAttribPointerv(206, 206),
+ glHint(207, 207),
+ glIsBuffer(208, 208),
+ glIsEnabled(209, 209),
+ glIsFenceNV(210, 210),
+ glIsFramebuffer(211, 211),
+ glIsFramebufferOES(212, 212),
+ glIsProgram(213, 213),
+ glIsRenderbuffer(214, 214),
+ glIsRenderbufferOES(215, 215),
+ glIsShader(216, 216),
+ glIsTexture(217, 217),
+ glIsVertexArrayOES(218, 218),
+ glLightf(219, 219),
+ glLightfv(220, 220),
+ glLightModelf(221, 221),
+ glLightModelfv(222, 222),
+ glLightModelx(223, 223),
+ glLightModelxOES(224, 224),
+ glLightModelxv(225, 225),
+ glLightModelxvOES(226, 226),
+ glLightx(227, 227),
+ glLightxOES(228, 228),
+ glLightxv(229, 229),
+ glLightxvOES(230, 230),
+ glLineWidth(231, 231),
+ glLineWidthx(232, 232),
+ glLineWidthxOES(233, 233),
+ glLinkProgram(234, 234),
+ glLoadIdentity(235, 235),
+ glLoadMatrixf(236, 236),
+ glLoadMatrixx(237, 237),
+ glLoadMatrixxOES(238, 238),
+ glLoadPaletteFromModelViewMatrixOES(239, 239),
+ glLogicOp(240, 240),
+ glMapBufferOES(241, 241),
+ glMaterialf(242, 242),
+ glMaterialfv(243, 243),
+ glMaterialx(244, 244),
+ glMaterialxOES(245, 245),
+ glMaterialxv(246, 246),
+ glMaterialxvOES(247, 247),
+ glMatrixIndexPointerOES(248, 248),
+ glMatrixMode(249, 249),
+ glMultiDrawArraysEXT(250, 250),
+ glMultiDrawElementsEXT(251, 251),
+ glMultiTexCoord4f(252, 252),
+ glMultiTexCoord4x(253, 253),
+ glMultiTexCoord4xOES(254, 254),
+ glMultMatrixf(255, 255),
+ glMultMatrixx(256, 256),
+ glMultMatrixxOES(257, 257),
+ glNormal3f(258, 258),
+ glNormal3x(259, 259),
+ glNormal3xOES(260, 260),
+ glNormalPointer(261, 261),
+ glOrthof(262, 262),
+ glOrthofOES(263, 263),
+ glOrthox(264, 264),
+ glOrthoxOES(265, 265),
+ glPixelStorei(266, 266),
+ glPointParameterf(267, 267),
+ glPointParameterfv(268, 268),
+ glPointParameterx(269, 269),
+ glPointParameterxOES(270, 270),
+ glPointParameterxv(271, 271),
+ glPointParameterxvOES(272, 272),
+ glPointSize(273, 273),
+ glPointSizePointerOES(274, 274),
+ glPointSizex(275, 275),
+ glPointSizexOES(276, 276),
+ glPolygonOffset(277, 277),
+ glPolygonOffsetx(278, 278),
+ glPolygonOffsetxOES(279, 279),
+ glPopMatrix(280, 280),
+ glProgramBinaryOES(281, 281),
+ glPushMatrix(282, 282),
+ glQueryMatrixxOES(283, 283),
+ glReadPixels(284, 284),
+ glReleaseShaderCompiler(285, 285),
+ glRenderbufferStorage(286, 286),
+ glRenderbufferStorageMultisampleIMG(287, 287),
+ glRenderbufferStorageOES(288, 288),
+ glRotatef(289, 289),
+ glRotatex(290, 290),
+ glRotatexOES(291, 291),
+ glSampleCoverage(292, 292),
+ glSampleCoveragex(293, 293),
+ glSampleCoveragexOES(294, 294),
+ glScalef(295, 295),
+ glScalex(296, 296),
+ glScalexOES(297, 297),
+ glScissor(298, 298),
+ glSelectPerfMonitorCountersAMD(299, 299),
+ glSetFenceNV(300, 300),
+ glShadeModel(301, 301),
+ glShaderBinary(302, 302),
+ glShaderSource(303, 303),
+ glStartTilingQCOM(304, 304),
+ glStencilFunc(305, 305),
+ glStencilFuncSeparate(306, 306),
+ glStencilMask(307, 307),
+ glStencilMaskSeparate(308, 308),
+ glStencilOp(309, 309),
+ glStencilOpSeparate(310, 310),
+ glTestFenceNV(311, 311),
+ glTexCoordPointer(312, 312),
+ glTexEnvf(313, 313),
+ glTexEnvfv(314, 314),
+ glTexEnvi(315, 315),
+ glTexEnviv(316, 316),
+ glTexEnvx(317, 317),
+ glTexEnvxOES(318, 318),
+ glTexEnvxv(319, 319),
+ glTexEnvxvOES(320, 320),
+ glTexGenfOES(321, 321),
+ glTexGenfvOES(322, 322),
+ glTexGeniOES(323, 323),
+ glTexGenivOES(324, 324),
+ glTexGenxOES(325, 325),
+ glTexGenxvOES(326, 326),
+ glTexImage2D(327, 327),
+ glTexImage3DOES(328, 328),
+ glTexParameterf(329, 329),
+ glTexParameterfv(330, 330),
+ glTexParameteri(331, 331),
+ glTexParameteriv(332, 332),
+ glTexParameterx(333, 333),
+ glTexParameterxOES(334, 334),
+ glTexParameterxv(335, 335),
+ glTexParameterxvOES(336, 336),
+ glTexSubImage2D(337, 337),
+ glTexSubImage3DOES(338, 338),
+ glTranslatef(339, 339),
+ glTranslatex(340, 340),
+ glTranslatexOES(341, 341),
+ glUniform1f(342, 342),
+ glUniform1fv(343, 343),
+ glUniform1i(344, 344),
+ glUniform1iv(345, 345),
+ glUniform2f(346, 346),
+ glUniform2fv(347, 347),
+ glUniform2i(348, 348),
+ glUniform2iv(349, 349),
+ glUniform3f(350, 350),
+ glUniform3fv(351, 351),
+ glUniform3i(352, 352),
+ glUniform3iv(353, 353),
+ glUniform4f(354, 354),
+ glUniform4fv(355, 355),
+ glUniform4i(356, 356),
+ glUniform4iv(357, 357),
+ glUniformMatrix2fv(358, 358),
+ glUniformMatrix3fv(359, 359),
+ glUniformMatrix4fv(360, 360),
+ glUnmapBufferOES(361, 361),
+ glUseProgram(362, 362),
+ glValidateProgram(363, 363),
+ glVertexAttrib1f(364, 364),
+ glVertexAttrib1fv(365, 365),
+ glVertexAttrib2f(366, 366),
+ glVertexAttrib2fv(367, 367),
+ glVertexAttrib3f(368, 368),
+ glVertexAttrib3fv(369, 369),
+ glVertexAttrib4f(370, 370),
+ glVertexAttrib4fv(371, 371),
+ glVertexAttribPointer(372, 372),
+ glVertexPointer(373, 373),
+ glViewport(374, 374),
+ glWeightPointerOES(375, 375),
+ glReadBuffer(376, 376),
+ glDrawRangeElements(377, 377),
+ glTexImage3D(378, 378),
+ glTexSubImage3D(379, 379),
+ glCopyTexSubImage3D(380, 380),
+ glCompressedTexImage3D(381, 381),
+ glCompressedTexSubImage3D(382, 382),
+ glGenQueries(383, 383),
+ glDeleteQueries(384, 384),
+ glIsQuery(385, 385),
+ glBeginQuery(386, 386),
+ glEndQuery(387, 387),
+ glGetQueryiv(388, 388),
+ glGetQueryObjectuiv(389, 389),
+ glUnmapBuffer(390, 390),
+ glGetBufferPointerv(391, 391),
+ glDrawBuffers(392, 392),
+ glUniformMatrix2x3fv(393, 393),
+ glUniformMatrix3x2fv(394, 394),
+ glUniformMatrix2x4fv(395, 395),
+ glUniformMatrix4x2fv(396, 396),
+ glUniformMatrix3x4fv(397, 397),
+ glUniformMatrix4x3fv(398, 398),
+ glBlitFramebuffer(399, 399),
+ glRenderbufferStorageMultisample(400, 400),
+ glFramebufferTextureLayer(401, 401),
+ glMapBufferRange(402, 402),
+ glFlushMappedBufferRange(403, 403),
+ glBindVertexArray(404, 404),
+ glDeleteVertexArrays(405, 405),
+ glGenVertexArrays(406, 406),
+ glIsVertexArray(407, 407),
+ glGetIntegeri_v(408, 408),
+ glBeginTransformFeedback(409, 409),
+ glEndTransformFeedback(410, 410),
+ glBindBufferRange(411, 411),
+ glBindBufferBase(412, 412),
+ glTransformFeedbackVaryings(413, 413),
+ glGetTransformFeedbackVarying(414, 414),
+ glVertexAttribIPointer(415, 415),
+ glGetVertexAttribIiv(416, 416),
+ glGetVertexAttribIuiv(417, 417),
+ glVertexAttribI4i(418, 418),
+ glVertexAttribI4ui(419, 419),
+ glVertexAttribI4iv(420, 420),
+ glVertexAttribI4uiv(421, 421),
+ glGetUniformuiv(422, 422),
+ glGetFragDataLocation(423, 423),
+ glUniform1ui(424, 424),
+ glUniform2ui(425, 425),
+ glUniform3ui(426, 426),
+ glUniform4ui(427, 427),
+ glUniform1uiv(428, 428),
+ glUniform2uiv(429, 429),
+ glUniform3uiv(430, 430),
+ glUniform4uiv(431, 431),
+ glClearBufferiv(432, 432),
+ glClearBufferuiv(433, 433),
+ glClearBufferfv(434, 434),
+ glClearBufferfi(435, 435),
+ glGetStringi(436, 436),
+ glCopyBufferSubData(437, 437),
+ glGetUniformIndices(438, 438),
+ glGetActiveUniformsiv(439, 439),
+ glGetUniformBlockIndex(440, 440),
+ glGetActiveUniformBlockiv(441, 441),
+ glGetActiveUniformBlockName(442, 442),
+ glUniformBlockBinding(443, 443),
+ glDrawArraysInstanced(444, 444),
+ glDrawElementsInstanced(445, 445),
+ glFenceSync(446, 446),
+ glIsSync(447, 447),
+ glDeleteSync(448, 448),
+ glClientWaitSync(449, 449),
+ glWaitSync(450, 450),
+ glGetInteger64v(451, 451),
+ glGetSynciv(452, 452),
+ glGetInteger64i_v(453, 453),
+ glGetBufferParameteri64v(454, 454),
+ glGenSamplers(455, 455),
+ glDeleteSamplers(456, 456),
+ glIsSampler(457, 457),
+ glBindSampler(458, 458),
+ glSamplerParameteri(459, 459),
+ glSamplerParameteriv(460, 460),
+ glSamplerParameterf(461, 461),
+ glSamplerParameterfv(462, 462),
+ glGetSamplerParameteriv(463, 463),
+ glGetSamplerParameterfv(464, 464),
+ glVertexAttribDivisor(465, 465),
+ glBindTransformFeedback(466, 466),
+ glDeleteTransformFeedbacks(467, 467),
+ glGenTransformFeedbacks(468, 468),
+ glIsTransformFeedback(469, 469),
+ glPauseTransformFeedback(470, 470),
+ glResumeTransformFeedback(471, 471),
+ glGetProgramBinary(472, 472),
+ glProgramBinary(473, 473),
+ glProgramParameteri(474, 474),
+ glInvalidateFramebuffer(475, 475),
+ glInvalidateSubFramebuffer(476, 476),
+ glTexStorage2D(477, 477),
+ glTexStorage3D(478, 478),
+ glGetInternalformativ(479, 479),
+ glActiveShaderProgramEXT(480, 502),
+ glAlphaFuncQCOM(481, 503),
+ glBeginQueryEXT(482, 504),
+ glBindProgramPipelineEXT(483, 505),
+ glBlitFramebufferANGLE(484, 506),
+ glCreateShaderProgramvEXT(485, 507),
+ glDeleteProgramPipelinesEXT(486, 508),
+ glDeleteQueriesEXT(487, 509),
+ glDrawBuffersNV(488, 510),
+ glEndQueryEXT(489, 511),
+ glFramebufferTexture2DMultisampleEXT(490, 512),
+ glGenProgramPipelinesEXT(491, 513),
+ glGenQueriesEXT(492, 514),
+ glGetGraphicsResetStatusEXT(493, 515),
+ glGetObjectLabelEXT(494, 516),
+ glGetProgramPipelineInfoLogEXT(495, 517),
+ glGetProgramPipelineivEXT(496, 518),
+ glGetQueryObjectuivEXT(497, 519),
+ glGetQueryivEXT(498, 520),
+ glGetnUniformfvEXT(499, 521),
+ glInsertEventMarkerEXT(501, 522),
+ glIsProgramPipelineEXT(502, 523),
+ glIsQueryEXT(503, 524),
+ glLabelObjectEXT(504, 525),
+ glPopGroupMarkerEXT(505, 526),
+ glProgramParameteriEXT(506, 527),
+ glProgramUniform1fEXT(507, 528),
+ glProgramUniform1fvEXT(508, 529),
+ glProgramUniform1iEXT(509, 530),
+ glProgramUniform1ivEXT(510, 531),
+ glProgramUniform2fEXT(511, 532),
+ glProgramUniform2fvEXT(512, 533),
+ glProgramUniform2iEXT(513, 534),
+ glProgramUniform2ivEXT(514, 535),
+ glProgramUniform3fEXT(515, 536),
+ glProgramUniform3fvEXT(516, 537),
+ glProgramUniform3iEXT(517, 538),
+ glProgramUniform3ivEXT(518, 539),
+ glProgramUniform4fEXT(519, 540),
+ glProgramUniform4fvEXT(520, 541),
+ glProgramUniform4iEXT(521, 542),
+ glProgramUniform4ivEXT(522, 543),
+ glProgramUniformMatrix2fvEXT(523, 544),
+ glProgramUniformMatrix3fvEXT(524, 545),
+ glProgramUniformMatrix4fvEXT(525, 546),
+ glPushGroupMarkerEXT(526, 547),
+ glReadBufferNV(527, 548),
+ glReadnPixelsEXT(528, 549),
+ glRenderbufferStorageMultisampleANGLE(529, 550),
+ glRenderbufferStorageMultisampleAPPLE(530, 551),
+ glRenderbufferStorageMultisampleEXT(531, 552),
+ glResolveMultisampleFramebufferAPPLE(532, 553),
+ glTexStorage1DEXT(533, 554),
+ glTexStorage2DEXT(534, 555),
+ glTexStorage3DEXT(535, 556),
+ glTextureStorage1DEXT(536, 557),
+ glTextureStorage2DEXT(537, 558),
+ glTextureStorage3DEXT(538, 559),
+ glUseProgramStagesEXT(539, 560),
+ glValidateProgramPipelineEXT(540, 561),
+ eglGetDisplay(541, 2000),
+ eglInitialize(542, 2001),
+ eglTerminate(543, 2002),
+ eglGetConfigs(544, 2003),
+ eglChooseConfig(545, 2004),
+ eglGetConfigAttrib(546, 2005),
+ eglCreateWindowSurface(547, 2006),
+ eglCreatePixmapSurface(548, 2007),
+ eglCreatePbufferSurface(549, 2008),
+ eglDestroySurface(550, 2009),
+ eglQuerySurface(551, 2010),
+ eglCreateContext(552, 2011),
+ eglDestroyContext(553, 2012),
+ eglMakeCurrent(554, 2013),
+ eglGetCurrentContext(555, 2014),
+ eglGetCurrentSurface(556, 2015),
+ eglGetCurrentDisplay(557, 2016),
+ eglQueryContext(558, 2017),
+ eglWaitGL(559, 2018),
+ eglWaitNative(560, 2019),
+ eglSwapBuffers(561, 2020),
+ eglCopyBuffers(562, 2021),
+ eglGetError(563, 2022),
+ eglQueryString(564, 2023),
+ eglGetProcAddress(565, 2024),
+ eglSurfaceAttrib(566, 2025),
+ eglBindTexImage(567, 2026),
+ eglReleaseTexImage(568, 2027),
+ eglSwapInterval(569, 2028),
+ eglBindAPI(570, 2029),
+ eglQueryAPI(571, 2030),
+ eglWaitClient(572, 2031),
+ eglReleaseThread(573, 2032),
+ eglCreatePbufferFromClientBuffer(574, 2033),
+ eglLockSurfaceKHR(575, 2034),
+ eglUnlockSurfaceKHR(576, 2035),
+ eglCreateImageKHR(577, 2036),
+ eglDestroyImageKHR(578, 2037),
+ eglCreateSyncKHR(579, 2038),
+ eglDestroySyncKHR(580, 2039),
+ eglClientWaitSyncKHR(581, 2040),
+ eglGetSyncAttribKHR(582, 2041),
+ eglSetSwapRectangleANDROID(583, 2042),
+ eglGetRenderBufferANDROID(584, 2043),
+ eglGetSystemTimeFrequencyNV(585, 2044),
+ eglGetSystemTimeNV(586, 2045),
+ invalid(587, 3000),
+ glVertexAttribPointerData(588, 3001),
+ ;
+
+ public static final Function glGetnUniformivEXT = glGetnUniformfvEXT;
+
+ @Override
+ public final int getNumber() { return value; }
+
+ public static Function valueOf(int value) {
+ switch (value) {
+ case 0: return glActiveTexture;
+ case 1: return glAlphaFunc;
+ case 2: return glAlphaFuncx;
+ case 3: return glAlphaFuncxOES;
+ case 4: return glAttachShader;
+ case 5: return glBeginPerfMonitorAMD;
+ case 6: return glBindAttribLocation;
+ case 7: return glBindBuffer;
+ case 8: return glBindFramebuffer;
+ case 9: return glBindFramebufferOES;
+ case 10: return glBindRenderbuffer;
+ case 11: return glBindRenderbufferOES;
+ case 12: return glBindTexture;
+ case 13: return glBindVertexArrayOES;
+ case 14: return glBlendColor;
+ case 15: return glBlendEquation;
+ case 16: return glBlendEquationOES;
+ case 17: return glBlendEquationSeparate;
+ case 18: return glBlendEquationSeparateOES;
+ case 19: return glBlendFunc;
+ case 20: return glBlendFuncSeparate;
+ case 21: return glBlendFuncSeparateOES;
+ case 22: return glBufferData;
+ case 23: return glBufferSubData;
+ case 24: return glCheckFramebufferStatus;
+ case 25: return glCheckFramebufferStatusOES;
+ case 26: return glClearColor;
+ case 27: return glClearColorx;
+ case 28: return glClearColorxOES;
+ case 29: return glClearDepthf;
+ case 30: return glClearDepthfOES;
+ case 31: return glClearDepthx;
+ case 32: return glClearDepthxOES;
+ case 33: return glClear;
+ case 34: return glClearStencil;
+ case 35: return glClientActiveTexture;
+ case 36: return glClipPlanef;
+ case 37: return glClipPlanefIMG;
+ case 38: return glClipPlanefOES;
+ case 39: return glClipPlanex;
+ case 40: return glClipPlanexIMG;
+ case 41: return glClipPlanexOES;
+ case 42: return glColor4f;
+ case 43: return glColor4ub;
+ case 44: return glColor4x;
+ case 45: return glColor4xOES;
+ case 46: return glColorMask;
+ case 47: return glColorPointer;
+ case 48: return glCompileShader;
+ case 49: return glCompressedTexImage2D;
+ case 50: return glCompressedTexImage3DOES;
+ case 51: return glCompressedTexSubImage2D;
+ case 52: return glCompressedTexSubImage3DOES;
+ case 53: return glCopyTexImage2D;
+ case 54: return glCopyTexSubImage2D;
+ case 55: return glCopyTexSubImage3DOES;
+ case 56: return glCoverageMaskNV;
+ case 57: return glCoverageOperationNV;
+ case 58: return glCreateProgram;
+ case 59: return glCreateShader;
+ case 60: return glCullFace;
+ case 61: return glCurrentPaletteMatrixOES;
+ case 62: return glDeleteBuffers;
+ case 63: return glDeleteFencesNV;
+ case 64: return glDeleteFramebuffers;
+ case 65: return glDeleteFramebuffersOES;
+ case 66: return glDeletePerfMonitorsAMD;
+ case 67: return glDeleteProgram;
+ case 68: return glDeleteRenderbuffers;
+ case 69: return glDeleteRenderbuffersOES;
+ case 70: return glDeleteShader;
+ case 71: return glDeleteTextures;
+ case 72: return glDeleteVertexArraysOES;
+ case 73: return glDepthFunc;
+ case 74: return glDepthMask;
+ case 75: return glDepthRangef;
+ case 76: return glDepthRangefOES;
+ case 77: return glDepthRangex;
+ case 78: return glDepthRangexOES;
+ case 79: return glDetachShader;
+ case 80: return glDisableClientState;
+ case 81: return glDisableDriverControlQCOM;
+ case 82: return glDisable;
+ case 83: return glDisableVertexAttribArray;
+ case 84: return glDiscardFramebufferEXT;
+ case 85: return glDrawArrays;
+ case 86: return glDrawElements;
+ case 87: return glDrawTexfOES;
+ case 88: return glDrawTexfvOES;
+ case 89: return glDrawTexiOES;
+ case 90: return glDrawTexivOES;
+ case 91: return glDrawTexsOES;
+ case 92: return glDrawTexsvOES;
+ case 93: return glDrawTexxOES;
+ case 94: return glDrawTexxvOES;
+ case 95: return glEGLImageTargetRenderbufferStorageOES;
+ case 96: return glEGLImageTargetTexture2DOES;
+ case 97: return glEnableClientState;
+ case 98: return glEnableDriverControlQCOM;
+ case 99: return glEnable;
+ case 100: return glEnableVertexAttribArray;
+ case 101: return glEndPerfMonitorAMD;
+ case 102: return glEndTilingQCOM;
+ case 103: return glExtGetBufferPointervQCOM;
+ case 104: return glExtGetBuffersQCOM;
+ case 105: return glExtGetFramebuffersQCOM;
+ case 106: return glExtGetProgramBinarySourceQCOM;
+ case 107: return glExtGetProgramsQCOM;
+ case 108: return glExtGetRenderbuffersQCOM;
+ case 109: return glExtGetShadersQCOM;
+ case 110: return glExtGetTexLevelParameterivQCOM;
+ case 111: return glExtGetTexSubImageQCOM;
+ case 112: return glExtGetTexturesQCOM;
+ case 113: return glExtIsProgramBinaryQCOM;
+ case 114: return glExtTexObjectStateOverrideiQCOM;
+ case 115: return glFinishFenceNV;
+ case 116: return glFinish;
+ case 117: return glFlush;
+ case 118: return glFogf;
+ case 119: return glFogfv;
+ case 120: return glFogx;
+ case 121: return glFogxOES;
+ case 122: return glFogxv;
+ case 123: return glFogxvOES;
+ case 124: return glFramebufferRenderbuffer;
+ case 125: return glFramebufferRenderbufferOES;
+ case 126: return glFramebufferTexture2D;
+ case 127: return glFramebufferTexture2DMultisampleIMG;
+ case 128: return glFramebufferTexture2DOES;
+ case 129: return glFramebufferTexture3DOES;
+ case 130: return glFrontFace;
+ case 131: return glFrustumf;
+ case 132: return glFrustumfOES;
+ case 133: return glFrustumx;
+ case 134: return glFrustumxOES;
+ case 135: return glGenBuffers;
+ case 136: return glGenerateMipmap;
+ case 137: return glGenerateMipmapOES;
+ case 138: return glGenFencesNV;
+ case 139: return glGenFramebuffers;
+ case 140: return glGenFramebuffersOES;
+ case 141: return glGenPerfMonitorsAMD;
+ case 142: return glGenRenderbuffers;
+ case 143: return glGenRenderbuffersOES;
+ case 144: return glGenTextures;
+ case 145: return glGenVertexArraysOES;
+ case 146: return glGetActiveAttrib;
+ case 147: return glGetActiveUniform;
+ case 148: return glGetAttachedShaders;
+ case 149: return glGetAttribLocation;
+ case 150: return glGetBooleanv;
+ case 151: return glGetBufferParameteriv;
+ case 152: return glGetBufferPointervOES;
+ case 153: return glGetClipPlanef;
+ case 154: return glGetClipPlanefOES;
+ case 155: return glGetClipPlanex;
+ case 156: return glGetClipPlanexOES;
+ case 157: return glGetDriverControlsQCOM;
+ case 158: return glGetDriverControlStringQCOM;
+ case 159: return glGetError;
+ case 160: return glGetFenceivNV;
+ case 161: return glGetFixedv;
+ case 162: return glGetFixedvOES;
+ case 163: return glGetFloatv;
+ case 164: return glGetFramebufferAttachmentParameteriv;
+ case 165: return glGetFramebufferAttachmentParameterivOES;
+ case 166: return glGetIntegerv;
+ case 167: return glGetLightfv;
+ case 168: return glGetLightxv;
+ case 169: return glGetLightxvOES;
+ case 170: return glGetMaterialfv;
+ case 171: return glGetMaterialxv;
+ case 172: return glGetMaterialxvOES;
+ case 173: return glGetPerfMonitorCounterDataAMD;
+ case 174: return glGetPerfMonitorCounterInfoAMD;
+ case 175: return glGetPerfMonitorCountersAMD;
+ case 176: return glGetPerfMonitorCounterStringAMD;
+ case 177: return glGetPerfMonitorGroupsAMD;
+ case 178: return glGetPerfMonitorGroupStringAMD;
+ case 179: return glGetPointerv;
+ case 180: return glGetProgramBinaryOES;
+ case 181: return glGetProgramInfoLog;
+ case 182: return glGetProgramiv;
+ case 183: return glGetRenderbufferParameteriv;
+ case 184: return glGetRenderbufferParameterivOES;
+ case 185: return glGetShaderInfoLog;
+ case 186: return glGetShaderiv;
+ case 187: return glGetShaderPrecisionFormat;
+ case 188: return glGetShaderSource;
+ case 189: return glGetString;
+ case 190: return glGetTexEnvfv;
+ case 191: return glGetTexEnviv;
+ case 192: return glGetTexEnvxv;
+ case 193: return glGetTexEnvxvOES;
+ case 194: return glGetTexGenfvOES;
+ case 195: return glGetTexGenivOES;
+ case 196: return glGetTexGenxvOES;
+ case 197: return glGetTexParameterfv;
+ case 198: return glGetTexParameteriv;
+ case 199: return glGetTexParameterxv;
+ case 200: return glGetTexParameterxvOES;
+ case 201: return glGetUniformfv;
+ case 202: return glGetUniformiv;
+ case 203: return glGetUniformLocation;
+ case 204: return glGetVertexAttribfv;
+ case 205: return glGetVertexAttribiv;
+ case 206: return glGetVertexAttribPointerv;
+ case 207: return glHint;
+ case 208: return glIsBuffer;
+ case 209: return glIsEnabled;
+ case 210: return glIsFenceNV;
+ case 211: return glIsFramebuffer;
+ case 212: return glIsFramebufferOES;
+ case 213: return glIsProgram;
+ case 214: return glIsRenderbuffer;
+ case 215: return glIsRenderbufferOES;
+ case 216: return glIsShader;
+ case 217: return glIsTexture;
+ case 218: return glIsVertexArrayOES;
+ case 219: return glLightf;
+ case 220: return glLightfv;
+ case 221: return glLightModelf;
+ case 222: return glLightModelfv;
+ case 223: return glLightModelx;
+ case 224: return glLightModelxOES;
+ case 225: return glLightModelxv;
+ case 226: return glLightModelxvOES;
+ case 227: return glLightx;
+ case 228: return glLightxOES;
+ case 229: return glLightxv;
+ case 230: return glLightxvOES;
+ case 231: return glLineWidth;
+ case 232: return glLineWidthx;
+ case 233: return glLineWidthxOES;
+ case 234: return glLinkProgram;
+ case 235: return glLoadIdentity;
+ case 236: return glLoadMatrixf;
+ case 237: return glLoadMatrixx;
+ case 238: return glLoadMatrixxOES;
+ case 239: return glLoadPaletteFromModelViewMatrixOES;
+ case 240: return glLogicOp;
+ case 241: return glMapBufferOES;
+ case 242: return glMaterialf;
+ case 243: return glMaterialfv;
+ case 244: return glMaterialx;
+ case 245: return glMaterialxOES;
+ case 246: return glMaterialxv;
+ case 247: return glMaterialxvOES;
+ case 248: return glMatrixIndexPointerOES;
+ case 249: return glMatrixMode;
+ case 250: return glMultiDrawArraysEXT;
+ case 251: return glMultiDrawElementsEXT;
+ case 252: return glMultiTexCoord4f;
+ case 253: return glMultiTexCoord4x;
+ case 254: return glMultiTexCoord4xOES;
+ case 255: return glMultMatrixf;
+ case 256: return glMultMatrixx;
+ case 257: return glMultMatrixxOES;
+ case 258: return glNormal3f;
+ case 259: return glNormal3x;
+ case 260: return glNormal3xOES;
+ case 261: return glNormalPointer;
+ case 262: return glOrthof;
+ case 263: return glOrthofOES;
+ case 264: return glOrthox;
+ case 265: return glOrthoxOES;
+ case 266: return glPixelStorei;
+ case 267: return glPointParameterf;
+ case 268: return glPointParameterfv;
+ case 269: return glPointParameterx;
+ case 270: return glPointParameterxOES;
+ case 271: return glPointParameterxv;
+ case 272: return glPointParameterxvOES;
+ case 273: return glPointSize;
+ case 274: return glPointSizePointerOES;
+ case 275: return glPointSizex;
+ case 276: return glPointSizexOES;
+ case 277: return glPolygonOffset;
+ case 278: return glPolygonOffsetx;
+ case 279: return glPolygonOffsetxOES;
+ case 280: return glPopMatrix;
+ case 281: return glProgramBinaryOES;
+ case 282: return glPushMatrix;
+ case 283: return glQueryMatrixxOES;
+ case 284: return glReadPixels;
+ case 285: return glReleaseShaderCompiler;
+ case 286: return glRenderbufferStorage;
+ case 287: return glRenderbufferStorageMultisampleIMG;
+ case 288: return glRenderbufferStorageOES;
+ case 289: return glRotatef;
+ case 290: return glRotatex;
+ case 291: return glRotatexOES;
+ case 292: return glSampleCoverage;
+ case 293: return glSampleCoveragex;
+ case 294: return glSampleCoveragexOES;
+ case 295: return glScalef;
+ case 296: return glScalex;
+ case 297: return glScalexOES;
+ case 298: return glScissor;
+ case 299: return glSelectPerfMonitorCountersAMD;
+ case 300: return glSetFenceNV;
+ case 301: return glShadeModel;
+ case 302: return glShaderBinary;
+ case 303: return glShaderSource;
+ case 304: return glStartTilingQCOM;
+ case 305: return glStencilFunc;
+ case 306: return glStencilFuncSeparate;
+ case 307: return glStencilMask;
+ case 308: return glStencilMaskSeparate;
+ case 309: return glStencilOp;
+ case 310: return glStencilOpSeparate;
+ case 311: return glTestFenceNV;
+ case 312: return glTexCoordPointer;
+ case 313: return glTexEnvf;
+ case 314: return glTexEnvfv;
+ case 315: return glTexEnvi;
+ case 316: return glTexEnviv;
+ case 317: return glTexEnvx;
+ case 318: return glTexEnvxOES;
+ case 319: return glTexEnvxv;
+ case 320: return glTexEnvxvOES;
+ case 321: return glTexGenfOES;
+ case 322: return glTexGenfvOES;
+ case 323: return glTexGeniOES;
+ case 324: return glTexGenivOES;
+ case 325: return glTexGenxOES;
+ case 326: return glTexGenxvOES;
+ case 327: return glTexImage2D;
+ case 328: return glTexImage3DOES;
+ case 329: return glTexParameterf;
+ case 330: return glTexParameterfv;
+ case 331: return glTexParameteri;
+ case 332: return glTexParameteriv;
+ case 333: return glTexParameterx;
+ case 334: return glTexParameterxOES;
+ case 335: return glTexParameterxv;
+ case 336: return glTexParameterxvOES;
+ case 337: return glTexSubImage2D;
+ case 338: return glTexSubImage3DOES;
+ case 339: return glTranslatef;
+ case 340: return glTranslatex;
+ case 341: return glTranslatexOES;
+ case 342: return glUniform1f;
+ case 343: return glUniform1fv;
+ case 344: return glUniform1i;
+ case 345: return glUniform1iv;
+ case 346: return glUniform2f;
+ case 347: return glUniform2fv;
+ case 348: return glUniform2i;
+ case 349: return glUniform2iv;
+ case 350: return glUniform3f;
+ case 351: return glUniform3fv;
+ case 352: return glUniform3i;
+ case 353: return glUniform3iv;
+ case 354: return glUniform4f;
+ case 355: return glUniform4fv;
+ case 356: return glUniform4i;
+ case 357: return glUniform4iv;
+ case 358: return glUniformMatrix2fv;
+ case 359: return glUniformMatrix3fv;
+ case 360: return glUniformMatrix4fv;
+ case 361: return glUnmapBufferOES;
+ case 362: return glUseProgram;
+ case 363: return glValidateProgram;
+ case 364: return glVertexAttrib1f;
+ case 365: return glVertexAttrib1fv;
+ case 366: return glVertexAttrib2f;
+ case 367: return glVertexAttrib2fv;
+ case 368: return glVertexAttrib3f;
+ case 369: return glVertexAttrib3fv;
+ case 370: return glVertexAttrib4f;
+ case 371: return glVertexAttrib4fv;
+ case 372: return glVertexAttribPointer;
+ case 373: return glVertexPointer;
+ case 374: return glViewport;
+ case 375: return glWeightPointerOES;
+ case 376: return glReadBuffer;
+ case 377: return glDrawRangeElements;
+ case 378: return glTexImage3D;
+ case 379: return glTexSubImage3D;
+ case 380: return glCopyTexSubImage3D;
+ case 381: return glCompressedTexImage3D;
+ case 382: return glCompressedTexSubImage3D;
+ case 383: return glGenQueries;
+ case 384: return glDeleteQueries;
+ case 385: return glIsQuery;
+ case 386: return glBeginQuery;
+ case 387: return glEndQuery;
+ case 388: return glGetQueryiv;
+ case 389: return glGetQueryObjectuiv;
+ case 390: return glUnmapBuffer;
+ case 391: return glGetBufferPointerv;
+ case 392: return glDrawBuffers;
+ case 393: return glUniformMatrix2x3fv;
+ case 394: return glUniformMatrix3x2fv;
+ case 395: return glUniformMatrix2x4fv;
+ case 396: return glUniformMatrix4x2fv;
+ case 397: return glUniformMatrix3x4fv;
+ case 398: return glUniformMatrix4x3fv;
+ case 399: return glBlitFramebuffer;
+ case 400: return glRenderbufferStorageMultisample;
+ case 401: return glFramebufferTextureLayer;
+ case 402: return glMapBufferRange;
+ case 403: return glFlushMappedBufferRange;
+ case 404: return glBindVertexArray;
+ case 405: return glDeleteVertexArrays;
+ case 406: return glGenVertexArrays;
+ case 407: return glIsVertexArray;
+ case 408: return glGetIntegeri_v;
+ case 409: return glBeginTransformFeedback;
+ case 410: return glEndTransformFeedback;
+ case 411: return glBindBufferRange;
+ case 412: return glBindBufferBase;
+ case 413: return glTransformFeedbackVaryings;
+ case 414: return glGetTransformFeedbackVarying;
+ case 415: return glVertexAttribIPointer;
+ case 416: return glGetVertexAttribIiv;
+ case 417: return glGetVertexAttribIuiv;
+ case 418: return glVertexAttribI4i;
+ case 419: return glVertexAttribI4ui;
+ case 420: return glVertexAttribI4iv;
+ case 421: return glVertexAttribI4uiv;
+ case 422: return glGetUniformuiv;
+ case 423: return glGetFragDataLocation;
+ case 424: return glUniform1ui;
+ case 425: return glUniform2ui;
+ case 426: return glUniform3ui;
+ case 427: return glUniform4ui;
+ case 428: return glUniform1uiv;
+ case 429: return glUniform2uiv;
+ case 430: return glUniform3uiv;
+ case 431: return glUniform4uiv;
+ case 432: return glClearBufferiv;
+ case 433: return glClearBufferuiv;
+ case 434: return glClearBufferfv;
+ case 435: return glClearBufferfi;
+ case 436: return glGetStringi;
+ case 437: return glCopyBufferSubData;
+ case 438: return glGetUniformIndices;
+ case 439: return glGetActiveUniformsiv;
+ case 440: return glGetUniformBlockIndex;
+ case 441: return glGetActiveUniformBlockiv;
+ case 442: return glGetActiveUniformBlockName;
+ case 443: return glUniformBlockBinding;
+ case 444: return glDrawArraysInstanced;
+ case 445: return glDrawElementsInstanced;
+ case 446: return glFenceSync;
+ case 447: return glIsSync;
+ case 448: return glDeleteSync;
+ case 449: return glClientWaitSync;
+ case 450: return glWaitSync;
+ case 451: return glGetInteger64v;
+ case 452: return glGetSynciv;
+ case 453: return glGetInteger64i_v;
+ case 454: return glGetBufferParameteri64v;
+ case 455: return glGenSamplers;
+ case 456: return glDeleteSamplers;
+ case 457: return glIsSampler;
+ case 458: return glBindSampler;
+ case 459: return glSamplerParameteri;
+ case 460: return glSamplerParameteriv;
+ case 461: return glSamplerParameterf;
+ case 462: return glSamplerParameterfv;
+ case 463: return glGetSamplerParameteriv;
+ case 464: return glGetSamplerParameterfv;
+ case 465: return glVertexAttribDivisor;
+ case 466: return glBindTransformFeedback;
+ case 467: return glDeleteTransformFeedbacks;
+ case 468: return glGenTransformFeedbacks;
+ case 469: return glIsTransformFeedback;
+ case 470: return glPauseTransformFeedback;
+ case 471: return glResumeTransformFeedback;
+ case 472: return glGetProgramBinary;
+ case 473: return glProgramBinary;
+ case 474: return glProgramParameteri;
+ case 475: return glInvalidateFramebuffer;
+ case 476: return glInvalidateSubFramebuffer;
+ case 477: return glTexStorage2D;
+ case 478: return glTexStorage3D;
+ case 479: return glGetInternalformativ;
+ case 502: return glActiveShaderProgramEXT;
+ case 503: return glAlphaFuncQCOM;
+ case 504: return glBeginQueryEXT;
+ case 505: return glBindProgramPipelineEXT;
+ case 506: return glBlitFramebufferANGLE;
+ case 507: return glCreateShaderProgramvEXT;
+ case 508: return glDeleteProgramPipelinesEXT;
+ case 509: return glDeleteQueriesEXT;
+ case 510: return glDrawBuffersNV;
+ case 511: return glEndQueryEXT;
+ case 512: return glFramebufferTexture2DMultisampleEXT;
+ case 513: return glGenProgramPipelinesEXT;
+ case 514: return glGenQueriesEXT;
+ case 515: return glGetGraphicsResetStatusEXT;
+ case 516: return glGetObjectLabelEXT;
+ case 517: return glGetProgramPipelineInfoLogEXT;
+ case 518: return glGetProgramPipelineivEXT;
+ case 519: return glGetQueryObjectuivEXT;
+ case 520: return glGetQueryivEXT;
+ case 521: return glGetnUniformfvEXT;
+ case 522: return glInsertEventMarkerEXT;
+ case 523: return glIsProgramPipelineEXT;
+ case 524: return glIsQueryEXT;
+ case 525: return glLabelObjectEXT;
+ case 526: return glPopGroupMarkerEXT;
+ case 527: return glProgramParameteriEXT;
+ case 528: return glProgramUniform1fEXT;
+ case 529: return glProgramUniform1fvEXT;
+ case 530: return glProgramUniform1iEXT;
+ case 531: return glProgramUniform1ivEXT;
+ case 532: return glProgramUniform2fEXT;
+ case 533: return glProgramUniform2fvEXT;
+ case 534: return glProgramUniform2iEXT;
+ case 535: return glProgramUniform2ivEXT;
+ case 536: return glProgramUniform3fEXT;
+ case 537: return glProgramUniform3fvEXT;
+ case 538: return glProgramUniform3iEXT;
+ case 539: return glProgramUniform3ivEXT;
+ case 540: return glProgramUniform4fEXT;
+ case 541: return glProgramUniform4fvEXT;
+ case 542: return glProgramUniform4iEXT;
+ case 543: return glProgramUniform4ivEXT;
+ case 544: return glProgramUniformMatrix2fvEXT;
+ case 545: return glProgramUniformMatrix3fvEXT;
+ case 546: return glProgramUniformMatrix4fvEXT;
+ case 547: return glPushGroupMarkerEXT;
+ case 548: return glReadBufferNV;
+ case 549: return glReadnPixelsEXT;
+ case 550: return glRenderbufferStorageMultisampleANGLE;
+ case 551: return glRenderbufferStorageMultisampleAPPLE;
+ case 552: return glRenderbufferStorageMultisampleEXT;
+ case 553: return glResolveMultisampleFramebufferAPPLE;
+ case 554: return glTexStorage1DEXT;
+ case 555: return glTexStorage2DEXT;
+ case 556: return glTexStorage3DEXT;
+ case 557: return glTextureStorage1DEXT;
+ case 558: return glTextureStorage2DEXT;
+ case 559: return glTextureStorage3DEXT;
+ case 560: return glUseProgramStagesEXT;
+ case 561: return glValidateProgramPipelineEXT;
+ case 2000: return eglGetDisplay;
+ case 2001: return eglInitialize;
+ case 2002: return eglTerminate;
+ case 2003: return eglGetConfigs;
+ case 2004: return eglChooseConfig;
+ case 2005: return eglGetConfigAttrib;
+ case 2006: return eglCreateWindowSurface;
+ case 2007: return eglCreatePixmapSurface;
+ case 2008: return eglCreatePbufferSurface;
+ case 2009: return eglDestroySurface;
+ case 2010: return eglQuerySurface;
+ case 2011: return eglCreateContext;
+ case 2012: return eglDestroyContext;
+ case 2013: return eglMakeCurrent;
+ case 2014: return eglGetCurrentContext;
+ case 2015: return eglGetCurrentSurface;
+ case 2016: return eglGetCurrentDisplay;
+ case 2017: return eglQueryContext;
+ case 2018: return eglWaitGL;
+ case 2019: return eglWaitNative;
+ case 2020: return eglSwapBuffers;
+ case 2021: return eglCopyBuffers;
+ case 2022: return eglGetError;
+ case 2023: return eglQueryString;
+ case 2024: return eglGetProcAddress;
+ case 2025: return eglSurfaceAttrib;
+ case 2026: return eglBindTexImage;
+ case 2027: return eglReleaseTexImage;
+ case 2028: return eglSwapInterval;
+ case 2029: return eglBindAPI;
+ case 2030: return eglQueryAPI;
+ case 2031: return eglWaitClient;
+ case 2032: return eglReleaseThread;
+ case 2033: return eglCreatePbufferFromClientBuffer;
+ case 2034: return eglLockSurfaceKHR;
+ case 2035: return eglUnlockSurfaceKHR;
+ case 2036: return eglCreateImageKHR;
+ case 2037: return eglDestroyImageKHR;
+ case 2038: return eglCreateSyncKHR;
+ case 2039: return eglDestroySyncKHR;
+ case 2040: return eglClientWaitSyncKHR;
+ case 2041: return eglGetSyncAttribKHR;
+ case 2042: return eglSetSwapRectangleANDROID;
+ case 2043: return eglGetRenderBufferANDROID;
+ case 2044: return eglGetSystemTimeFrequencyNV;
+ case 2045: return eglGetSystemTimeNV;
+ case 3000: return invalid;
+ case 3001: return glVertexAttribPointerData;
+ default: return null;
+ }
+ }
+
+ public static com.google.protobuf.Internal.EnumLiteMap<Function>
+ internalGetValueMap() {
+ return internalValueMap;
+ }
+ private static com.google.protobuf.Internal.EnumLiteMap<Function>
+ internalValueMap =
+ new com.google.protobuf.Internal.EnumLiteMap<Function>() {
+ @Override
+ public Function findValueByNumber(int number) {
+ return Function.valueOf(number)
+ ; }
+ };
+
+ private final int index;
+ private final int value;
+ private Function(int index, int value) {
+ this.index = index;
+ this.value = value;
+ }
+
+ // @@protoc_insertion_point(enum_scope:android.gltrace.GLMessage.Function)
+ }
+
+ public static final class DataType extends
+ com.google.protobuf.GeneratedMessageLite {
+ // Use DataType.newBuilder() to construct.
+ private DataType() {
+ initFields();
+ }
+ private DataType(boolean noInit) {}
+
+ private static final DataType defaultInstance;
+ public static DataType getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ @Override
+ public DataType getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public enum Type
+ implements com.google.protobuf.Internal.EnumLite {
+ VOID(0, 1),
+ CHAR(1, 2),
+ BYTE(2, 3),
+ INT(3, 4),
+ FLOAT(4, 5),
+ BOOL(5, 6),
+ ENUM(6, 7),
+ INT64(7, 8),
+ ;
+
+
+ @Override
+ public final int getNumber() { return value; }
+
+ public static Type valueOf(int value) {
+ switch (value) {
+ case 1: return VOID;
+ case 2: return CHAR;
+ case 3: return BYTE;
+ case 4: return INT;
+ case 5: return FLOAT;
+ case 6: return BOOL;
+ case 7: return ENUM;
+ case 8: return INT64;
+ default: return null;
+ }
+ }
+
+ public static com.google.protobuf.Internal.EnumLiteMap<Type>
+ internalGetValueMap() {
+ return internalValueMap;
+ }
+ private static com.google.protobuf.Internal.EnumLiteMap<Type>
+ internalValueMap =
+ new com.google.protobuf.Internal.EnumLiteMap<Type>() {
+ @Override
+ public Type findValueByNumber(int number) {
+ return Type.valueOf(number)
+ ; }
+ };
+
+ private final int index;
+ private final int value;
+ private Type(int index, int value) {
+ this.index = index;
+ this.value = value;
+ }
+
+ // @@protoc_insertion_point(enum_scope:android.gltrace.GLMessage.DataType.Type)
+ }
+
+ // required .android.gltrace.GLMessage.DataType.Type type = 1 [default = VOID];
+ public static final int TYPE_FIELD_NUMBER = 1;
+ private boolean hasType;
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type type_;
+ public boolean hasType() { return hasType; }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type getType() { return type_; }
+
+ // required bool isArray = 2 [default = false];
+ public static final int ISARRAY_FIELD_NUMBER = 2;
+ private boolean hasIsArray;
+ private boolean isArray_ = false;
+ public boolean hasIsArray() { return hasIsArray; }
+ public boolean getIsArray() { return isArray_; }
+
+ // repeated int32 intValue = 3;
+ public static final int INTVALUE_FIELD_NUMBER = 3;
+ private java.util.List<java.lang.Integer> intValue_ =
+ java.util.Collections.emptyList();
+ public java.util.List<java.lang.Integer> getIntValueList() {
+ return intValue_;
+ }
+ public int getIntValueCount() { return intValue_.size(); }
+ public int getIntValue(int index) {
+ return intValue_.get(index);
+ }
+
+ // repeated float floatValue = 4;
+ public static final int FLOATVALUE_FIELD_NUMBER = 4;
+ private java.util.List<java.lang.Float> floatValue_ =
+ java.util.Collections.emptyList();
+ public java.util.List<java.lang.Float> getFloatValueList() {
+ return floatValue_;
+ }
+ public int getFloatValueCount() { return floatValue_.size(); }
+ public float getFloatValue(int index) {
+ return floatValue_.get(index);
+ }
+
+ // repeated bytes charValue = 5;
+ public static final int CHARVALUE_FIELD_NUMBER = 5;
+ private java.util.List<com.google.protobuf.ByteString> charValue_ =
+ java.util.Collections.emptyList();
+ public java.util.List<com.google.protobuf.ByteString> getCharValueList() {
+ return charValue_;
+ }
+ public int getCharValueCount() { return charValue_.size(); }
+ public com.google.protobuf.ByteString getCharValue(int index) {
+ return charValue_.get(index);
+ }
+
+ // repeated bytes rawBytes = 6;
+ public static final int RAWBYTES_FIELD_NUMBER = 6;
+ private java.util.List<com.google.protobuf.ByteString> rawBytes_ =
+ java.util.Collections.emptyList();
+ public java.util.List<com.google.protobuf.ByteString> getRawBytesList() {
+ return rawBytes_;
+ }
+ public int getRawBytesCount() { return rawBytes_.size(); }
+ public com.google.protobuf.ByteString getRawBytes(int index) {
+ return rawBytes_.get(index);
+ }
+
+ // repeated bool boolValue = 7;
+ public static final int BOOLVALUE_FIELD_NUMBER = 7;
+ private java.util.List<java.lang.Boolean> boolValue_ =
+ java.util.Collections.emptyList();
+ public java.util.List<java.lang.Boolean> getBoolValueList() {
+ return boolValue_;
+ }
+ public int getBoolValueCount() { return boolValue_.size(); }
+ public boolean getBoolValue(int index) {
+ return boolValue_.get(index);
+ }
+
+ // repeated int64 int64Value = 8;
+ public static final int INT64VALUE_FIELD_NUMBER = 8;
+ private java.util.List<java.lang.Long> int64Value_ =
+ java.util.Collections.emptyList();
+ public java.util.List<java.lang.Long> getInt64ValueList() {
+ return int64Value_;
+ }
+ public int getInt64ValueCount() { return int64Value_.size(); }
+ public long getInt64Value(int index) {
+ return int64Value_.get(index);
+ }
+
+ private void initFields() {
+ type_ = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type.VOID;
+ }
+ @Override
+ public final boolean isInitialized() {
+ if (!hasType) return false;
+ if (!hasIsArray) return false;
+ return true;
+ }
+
+ @Override
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (hasType()) {
+ output.writeEnum(1, getType().getNumber());
+ }
+ if (hasIsArray()) {
+ output.writeBool(2, getIsArray());
+ }
+ for (int element : getIntValueList()) {
+ output.writeInt32(3, element);
+ }
+ for (float element : getFloatValueList()) {
+ output.writeFloat(4, element);
+ }
+ for (com.google.protobuf.ByteString element : getCharValueList()) {
+ output.writeBytes(5, element);
+ }
+ for (com.google.protobuf.ByteString element : getRawBytesList()) {
+ output.writeBytes(6, element);
+ }
+ for (boolean element : getBoolValueList()) {
+ output.writeBool(7, element);
+ }
+ for (long element : getInt64ValueList()) {
+ output.writeInt64(8, element);
+ }
+ }
+
+ private int memoizedSerializedSize = -1;
+ @Override
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (hasType()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeEnumSize(1, getType().getNumber());
+ }
+ if (hasIsArray()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBoolSize(2, getIsArray());
+ }
+ {
+ int dataSize = 0;
+ for (int element : getIntValueList()) {
+ dataSize += com.google.protobuf.CodedOutputStream
+ .computeInt32SizeNoTag(element);
+ }
+ size += dataSize;
+ size += 1 * getIntValueList().size();
+ }
+ {
+ int dataSize = 0;
+ dataSize = 4 * getFloatValueList().size();
+ size += dataSize;
+ size += 1 * getFloatValueList().size();
+ }
+ {
+ int dataSize = 0;
+ for (com.google.protobuf.ByteString element : getCharValueList()) {
+ dataSize += com.google.protobuf.CodedOutputStream
+ .computeBytesSizeNoTag(element);
+ }
+ size += dataSize;
+ size += 1 * getCharValueList().size();
+ }
+ {
+ int dataSize = 0;
+ for (com.google.protobuf.ByteString element : getRawBytesList()) {
+ dataSize += com.google.protobuf.CodedOutputStream
+ .computeBytesSizeNoTag(element);
+ }
+ size += dataSize;
+ size += 1 * getRawBytesList().size();
+ }
+ {
+ int dataSize = 0;
+ dataSize = 1 * getBoolValueList().size();
+ size += dataSize;
+ size += 1 * getBoolValueList().size();
+ }
+ {
+ int dataSize = 0;
+ for (long element : getInt64ValueList()) {
+ dataSize += com.google.protobuf.CodedOutputStream
+ .computeInt64SizeNoTag(element);
+ }
+ size += dataSize;
+ size += 1 * getInt64ValueList().size();
+ }
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ @Override
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ @Override
+ public Builder toBuilder() { return newBuilder(this); }
+
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessageLite.Builder<
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType, Builder> {
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType result;
+
+ // Construct using com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.newBuilder()
+ private Builder() {}
+
+ private static Builder create() {
+ Builder builder = new Builder();
+ builder.result = new com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType();
+ return builder;
+ }
+
+ @Override
+ protected com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType internalGetResult() {
+ return result;
+ }
+
+ @Override
+ public Builder clear() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "Cannot call clear() after build().");
+ }
+ result = new com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType();
+ return this;
+ }
+
+ @Override
+ public Builder clone() {
+ return create().mergeFrom(result);
+ }
+
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType getDefaultInstanceForType() {
+ return com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.getDefaultInstance();
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return result.isInitialized();
+ }
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType build() {
+ if (result != null && !isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return buildPartial();
+ }
+
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ if (!isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return buildPartial();
+ }
+
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType buildPartial() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "build() has already been called on this Builder.");
+ }
+ if (result.intValue_ != java.util.Collections.EMPTY_LIST) {
+ result.intValue_ =
+ java.util.Collections.unmodifiableList(result.intValue_);
+ }
+ if (result.floatValue_ != java.util.Collections.EMPTY_LIST) {
+ result.floatValue_ =
+ java.util.Collections.unmodifiableList(result.floatValue_);
+ }
+ if (result.charValue_ != java.util.Collections.EMPTY_LIST) {
+ result.charValue_ =
+ java.util.Collections.unmodifiableList(result.charValue_);
+ }
+ if (result.rawBytes_ != java.util.Collections.EMPTY_LIST) {
+ result.rawBytes_ =
+ java.util.Collections.unmodifiableList(result.rawBytes_);
+ }
+ if (result.boolValue_ != java.util.Collections.EMPTY_LIST) {
+ result.boolValue_ =
+ java.util.Collections.unmodifiableList(result.boolValue_);
+ }
+ if (result.int64Value_ != java.util.Collections.EMPTY_LIST) {
+ result.int64Value_ =
+ java.util.Collections.unmodifiableList(result.int64Value_);
+ }
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType returnMe = result;
+ result = null;
+ return returnMe;
+ }
+
+ @Override
+ public Builder mergeFrom(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType other) {
+ if (other == com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.getDefaultInstance()) return this;
+ if (other.hasType()) {
+ setType(other.getType());
+ }
+ if (other.hasIsArray()) {
+ setIsArray(other.getIsArray());
+ }
+ if (!other.intValue_.isEmpty()) {
+ if (result.intValue_.isEmpty()) {
+ result.intValue_ = new java.util.ArrayList<java.lang.Integer>();
+ }
+ result.intValue_.addAll(other.intValue_);
+ }
+ if (!other.floatValue_.isEmpty()) {
+ if (result.floatValue_.isEmpty()) {
+ result.floatValue_ = new java.util.ArrayList<java.lang.Float>();
+ }
+ result.floatValue_.addAll(other.floatValue_);
+ }
+ if (!other.charValue_.isEmpty()) {
+ if (result.charValue_.isEmpty()) {
+ result.charValue_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ result.charValue_.addAll(other.charValue_);
+ }
+ if (!other.rawBytes_.isEmpty()) {
+ if (result.rawBytes_.isEmpty()) {
+ result.rawBytes_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ result.rawBytes_.addAll(other.rawBytes_);
+ }
+ if (!other.boolValue_.isEmpty()) {
+ if (result.boolValue_.isEmpty()) {
+ result.boolValue_ = new java.util.ArrayList<java.lang.Boolean>();
+ }
+ result.boolValue_.addAll(other.boolValue_);
+ }
+ if (!other.int64Value_.isEmpty()) {
+ if (result.int64Value_.isEmpty()) {
+ result.int64Value_ = new java.util.ArrayList<java.lang.Long>();
+ }
+ result.int64Value_.addAll(other.int64Value_);
+ }
+ return this;
+ }
+
+ @Override
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ return this;
+ default: {
+ if (!parseUnknownField(input, extensionRegistry, tag)) {
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ int rawValue = input.readEnum();
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type value = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type.valueOf(rawValue);
+ if (value != null) {
+ setType(value);
+ }
+ break;
+ }
+ case 16: {
+ setIsArray(input.readBool());
+ break;
+ }
+ case 24: {
+ addIntValue(input.readInt32());
+ break;
+ }
+ case 26: {
+ int length = input.readRawVarint32();
+ int limit = input.pushLimit(length);
+ while (input.getBytesUntilLimit() > 0) {
+ addIntValue(input.readInt32());
+ }
+ input.popLimit(limit);
+ break;
+ }
+ case 37: {
+ addFloatValue(input.readFloat());
+ break;
+ }
+ case 34: {
+ int length = input.readRawVarint32();
+ int limit = input.pushLimit(length);
+ while (input.getBytesUntilLimit() > 0) {
+ addFloatValue(input.readFloat());
+ }
+ input.popLimit(limit);
+ break;
+ }
+ case 42: {
+ addCharValue(input.readBytes());
+ break;
+ }
+ case 50: {
+ addRawBytes(input.readBytes());
+ break;
+ }
+ case 56: {
+ addBoolValue(input.readBool());
+ break;
+ }
+ case 58: {
+ int length = input.readRawVarint32();
+ int limit = input.pushLimit(length);
+ while (input.getBytesUntilLimit() > 0) {
+ addBoolValue(input.readBool());
+ }
+ input.popLimit(limit);
+ break;
+ }
+ case 64: {
+ addInt64Value(input.readInt64());
+ break;
+ }
+ case 66: {
+ int length = input.readRawVarint32();
+ int limit = input.pushLimit(length);
+ while (input.getBytesUntilLimit() > 0) {
+ addInt64Value(input.readInt64());
+ }
+ input.popLimit(limit);
+ break;
+ }
+ }
+ }
+ }
+
+
+ // required .android.gltrace.GLMessage.DataType.Type type = 1 [default = VOID];
+ public boolean hasType() {
+ return result.hasType();
+ }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type getType() {
+ return result.getType();
+ }
+ public Builder setType(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasType = true;
+ result.type_ = value;
+ return this;
+ }
+ public Builder clearType() {
+ result.hasType = false;
+ result.type_ = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type.VOID;
+ return this;
+ }
+
+ // required bool isArray = 2 [default = false];
+ public boolean hasIsArray() {
+ return result.hasIsArray();
+ }
+ public boolean getIsArray() {
+ return result.getIsArray();
+ }
+ public Builder setIsArray(boolean value) {
+ result.hasIsArray = true;
+ result.isArray_ = value;
+ return this;
+ }
+ public Builder clearIsArray() {
+ result.hasIsArray = false;
+ result.isArray_ = false;
+ return this;
+ }
+
+ // repeated int32 intValue = 3;
+ public java.util.List<java.lang.Integer> getIntValueList() {
+ return java.util.Collections.unmodifiableList(result.intValue_);
+ }
+ public int getIntValueCount() {
+ return result.getIntValueCount();
+ }
+ public int getIntValue(int index) {
+ return result.getIntValue(index);
+ }
+ public Builder setIntValue(int index, int value) {
+ result.intValue_.set(index, value);
+ return this;
+ }
+ public Builder addIntValue(int value) {
+ if (result.intValue_.isEmpty()) {
+ result.intValue_ = new java.util.ArrayList<java.lang.Integer>();
+ }
+ result.intValue_.add(value);
+ return this;
+ }
+ public Builder addAllIntValue(
+ java.lang.Iterable<? extends java.lang.Integer> values) {
+ if (result.intValue_.isEmpty()) {
+ result.intValue_ = new java.util.ArrayList<java.lang.Integer>();
+ }
+ super.addAll(values, result.intValue_);
+ return this;
+ }
+ public Builder clearIntValue() {
+ result.intValue_ = java.util.Collections.emptyList();
+ return this;
+ }
+
+ // repeated float floatValue = 4;
+ public java.util.List<java.lang.Float> getFloatValueList() {
+ return java.util.Collections.unmodifiableList(result.floatValue_);
+ }
+ public int getFloatValueCount() {
+ return result.getFloatValueCount();
+ }
+ public float getFloatValue(int index) {
+ return result.getFloatValue(index);
+ }
+ public Builder setFloatValue(int index, float value) {
+ result.floatValue_.set(index, value);
+ return this;
+ }
+ public Builder addFloatValue(float value) {
+ if (result.floatValue_.isEmpty()) {
+ result.floatValue_ = new java.util.ArrayList<java.lang.Float>();
+ }
+ result.floatValue_.add(value);
+ return this;
+ }
+ public Builder addAllFloatValue(
+ java.lang.Iterable<? extends java.lang.Float> values) {
+ if (result.floatValue_.isEmpty()) {
+ result.floatValue_ = new java.util.ArrayList<java.lang.Float>();
+ }
+ super.addAll(values, result.floatValue_);
+ return this;
+ }
+ public Builder clearFloatValue() {
+ result.floatValue_ = java.util.Collections.emptyList();
+ return this;
+ }
+
+ // repeated bytes charValue = 5;
+ public java.util.List<com.google.protobuf.ByteString> getCharValueList() {
+ return java.util.Collections.unmodifiableList(result.charValue_);
+ }
+ public int getCharValueCount() {
+ return result.getCharValueCount();
+ }
+ public com.google.protobuf.ByteString getCharValue(int index) {
+ return result.getCharValue(index);
+ }
+ public Builder setCharValue(int index, com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.charValue_.set(index, value);
+ return this;
+ }
+ public Builder addCharValue(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ if (result.charValue_.isEmpty()) {
+ result.charValue_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ result.charValue_.add(value);
+ return this;
+ }
+ public Builder addAllCharValue(
+ java.lang.Iterable<? extends com.google.protobuf.ByteString> values) {
+ if (result.charValue_.isEmpty()) {
+ result.charValue_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ super.addAll(values, result.charValue_);
+ return this;
+ }
+ public Builder clearCharValue() {
+ result.charValue_ = java.util.Collections.emptyList();
+ return this;
+ }
+
+ // repeated bytes rawBytes = 6;
+ public java.util.List<com.google.protobuf.ByteString> getRawBytesList() {
+ return java.util.Collections.unmodifiableList(result.rawBytes_);
+ }
+ public int getRawBytesCount() {
+ return result.getRawBytesCount();
+ }
+ public com.google.protobuf.ByteString getRawBytes(int index) {
+ return result.getRawBytes(index);
+ }
+ public Builder setRawBytes(int index, com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.rawBytes_.set(index, value);
+ return this;
+ }
+ public Builder addRawBytes(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ if (result.rawBytes_.isEmpty()) {
+ result.rawBytes_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ result.rawBytes_.add(value);
+ return this;
+ }
+ public Builder addAllRawBytes(
+ java.lang.Iterable<? extends com.google.protobuf.ByteString> values) {
+ if (result.rawBytes_.isEmpty()) {
+ result.rawBytes_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ super.addAll(values, result.rawBytes_);
+ return this;
+ }
+ public Builder clearRawBytes() {
+ result.rawBytes_ = java.util.Collections.emptyList();
+ return this;
+ }
+
+ // repeated bool boolValue = 7;
+ public java.util.List<java.lang.Boolean> getBoolValueList() {
+ return java.util.Collections.unmodifiableList(result.boolValue_);
+ }
+ public int getBoolValueCount() {
+ return result.getBoolValueCount();
+ }
+ public boolean getBoolValue(int index) {
+ return result.getBoolValue(index);
+ }
+ public Builder setBoolValue(int index, boolean value) {
+ result.boolValue_.set(index, value);
+ return this;
+ }
+ public Builder addBoolValue(boolean value) {
+ if (result.boolValue_.isEmpty()) {
+ result.boolValue_ = new java.util.ArrayList<java.lang.Boolean>();
+ }
+ result.boolValue_.add(value);
+ return this;
+ }
+ public Builder addAllBoolValue(
+ java.lang.Iterable<? extends java.lang.Boolean> values) {
+ if (result.boolValue_.isEmpty()) {
+ result.boolValue_ = new java.util.ArrayList<java.lang.Boolean>();
+ }
+ super.addAll(values, result.boolValue_);
+ return this;
+ }
+ public Builder clearBoolValue() {
+ result.boolValue_ = java.util.Collections.emptyList();
+ return this;
+ }
+
+ // repeated int64 int64Value = 8;
+ public java.util.List<java.lang.Long> getInt64ValueList() {
+ return java.util.Collections.unmodifiableList(result.int64Value_);
+ }
+ public int getInt64ValueCount() {
+ return result.getInt64ValueCount();
+ }
+ public long getInt64Value(int index) {
+ return result.getInt64Value(index);
+ }
+ public Builder setInt64Value(int index, long value) {
+ result.int64Value_.set(index, value);
+ return this;
+ }
+ public Builder addInt64Value(long value) {
+ if (result.int64Value_.isEmpty()) {
+ result.int64Value_ = new java.util.ArrayList<java.lang.Long>();
+ }
+ result.int64Value_.add(value);
+ return this;
+ }
+ public Builder addAllInt64Value(
+ java.lang.Iterable<? extends java.lang.Long> values) {
+ if (result.int64Value_.isEmpty()) {
+ result.int64Value_ = new java.util.ArrayList<java.lang.Long>();
+ }
+ super.addAll(values, result.int64Value_);
+ return this;
+ }
+ public Builder clearInt64Value() {
+ result.int64Value_ = java.util.Collections.emptyList();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:android.gltrace.GLMessage.DataType)
+ }
+
+ static {
+ defaultInstance = new DataType(true);
+ com.android.ide.eclipse.gltrace.GLProtoBuf.internalForceInit();
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage.DataType)
+ }
+
+ public static final class FrameBuffer extends
+ com.google.protobuf.GeneratedMessageLite {
+ // Use FrameBuffer.newBuilder() to construct.
+ private FrameBuffer() {
+ initFields();
+ }
+ private FrameBuffer(boolean noInit) {}
+
+ private static final FrameBuffer defaultInstance;
+ public static FrameBuffer getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ @Override
+ public FrameBuffer getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ // required int32 width = 1;
+ public static final int WIDTH_FIELD_NUMBER = 1;
+ private boolean hasWidth;
+ private int width_ = 0;
+ public boolean hasWidth() { return hasWidth; }
+ public int getWidth() { return width_; }
+
+ // required int32 height = 2;
+ public static final int HEIGHT_FIELD_NUMBER = 2;
+ private boolean hasHeight;
+ private int height_ = 0;
+ public boolean hasHeight() { return hasHeight; }
+ public int getHeight() { return height_; }
+
+ // repeated bytes contents = 3;
+ public static final int CONTENTS_FIELD_NUMBER = 3;
+ private java.util.List<com.google.protobuf.ByteString> contents_ =
+ java.util.Collections.emptyList();
+ public java.util.List<com.google.protobuf.ByteString> getContentsList() {
+ return contents_;
+ }
+ public int getContentsCount() { return contents_.size(); }
+ public com.google.protobuf.ByteString getContents(int index) {
+ return contents_.get(index);
+ }
+
+ private void initFields() {
+ }
+ @Override
+ public final boolean isInitialized() {
+ if (!hasWidth) return false;
+ if (!hasHeight) return false;
+ return true;
+ }
+
+ @Override
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (hasWidth()) {
+ output.writeInt32(1, getWidth());
+ }
+ if (hasHeight()) {
+ output.writeInt32(2, getHeight());
+ }
+ for (com.google.protobuf.ByteString element : getContentsList()) {
+ output.writeBytes(3, element);
+ }
+ }
+
+ private int memoizedSerializedSize = -1;
+ @Override
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (hasWidth()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(1, getWidth());
+ }
+ if (hasHeight()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(2, getHeight());
+ }
+ {
+ int dataSize = 0;
+ for (com.google.protobuf.ByteString element : getContentsList()) {
+ dataSize += com.google.protobuf.CodedOutputStream
+ .computeBytesSizeNoTag(element);
+ }
+ size += dataSize;
+ size += 1 * getContentsList().size();
+ }
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ @Override
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ @Override
+ public Builder toBuilder() { return newBuilder(this); }
+
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessageLite.Builder<
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer, Builder> {
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer result;
+
+ // Construct using com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.newBuilder()
+ private Builder() {}
+
+ private static Builder create() {
+ Builder builder = new Builder();
+ builder.result = new com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer();
+ return builder;
+ }
+
+ @Override
+ protected com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer internalGetResult() {
+ return result;
+ }
+
+ @Override
+ public Builder clear() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "Cannot call clear() after build().");
+ }
+ result = new com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer();
+ return this;
+ }
+
+ @Override
+ public Builder clone() {
+ return create().mergeFrom(result);
+ }
+
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer getDefaultInstanceForType() {
+ return com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.getDefaultInstance();
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return result.isInitialized();
+ }
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer build() {
+ if (result != null && !isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return buildPartial();
+ }
+
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ if (!isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return buildPartial();
+ }
+
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer buildPartial() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "build() has already been called on this Builder.");
+ }
+ if (result.contents_ != java.util.Collections.EMPTY_LIST) {
+ result.contents_ =
+ java.util.Collections.unmodifiableList(result.contents_);
+ }
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer returnMe = result;
+ result = null;
+ return returnMe;
+ }
+
+ @Override
+ public Builder mergeFrom(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer other) {
+ if (other == com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.getDefaultInstance()) return this;
+ if (other.hasWidth()) {
+ setWidth(other.getWidth());
+ }
+ if (other.hasHeight()) {
+ setHeight(other.getHeight());
+ }
+ if (!other.contents_.isEmpty()) {
+ if (result.contents_.isEmpty()) {
+ result.contents_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ result.contents_.addAll(other.contents_);
+ }
+ return this;
+ }
+
+ @Override
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ return this;
+ default: {
+ if (!parseUnknownField(input, extensionRegistry, tag)) {
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ setWidth(input.readInt32());
+ break;
+ }
+ case 16: {
+ setHeight(input.readInt32());
+ break;
+ }
+ case 26: {
+ addContents(input.readBytes());
+ break;
+ }
+ }
+ }
+ }
+
+
+ // required int32 width = 1;
+ public boolean hasWidth() {
+ return result.hasWidth();
+ }
+ public int getWidth() {
+ return result.getWidth();
+ }
+ public Builder setWidth(int value) {
+ result.hasWidth = true;
+ result.width_ = value;
+ return this;
+ }
+ public Builder clearWidth() {
+ result.hasWidth = false;
+ result.width_ = 0;
+ return this;
+ }
+
+ // required int32 height = 2;
+ public boolean hasHeight() {
+ return result.hasHeight();
+ }
+ public int getHeight() {
+ return result.getHeight();
+ }
+ public Builder setHeight(int value) {
+ result.hasHeight = true;
+ result.height_ = value;
+ return this;
+ }
+ public Builder clearHeight() {
+ result.hasHeight = false;
+ result.height_ = 0;
+ return this;
+ }
+
+ // repeated bytes contents = 3;
+ public java.util.List<com.google.protobuf.ByteString> getContentsList() {
+ return java.util.Collections.unmodifiableList(result.contents_);
+ }
+ public int getContentsCount() {
+ return result.getContentsCount();
+ }
+ public com.google.protobuf.ByteString getContents(int index) {
+ return result.getContents(index);
+ }
+ public Builder setContents(int index, com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.contents_.set(index, value);
+ return this;
+ }
+ public Builder addContents(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ if (result.contents_.isEmpty()) {
+ result.contents_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ result.contents_.add(value);
+ return this;
+ }
+ public Builder addAllContents(
+ java.lang.Iterable<? extends com.google.protobuf.ByteString> values) {
+ if (result.contents_.isEmpty()) {
+ result.contents_ = new java.util.ArrayList<com.google.protobuf.ByteString>();
+ }
+ super.addAll(values, result.contents_);
+ return this;
+ }
+ public Builder clearContents() {
+ result.contents_ = java.util.Collections.emptyList();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:android.gltrace.GLMessage.FrameBuffer)
+ }
+
+ static {
+ defaultInstance = new FrameBuffer(true);
+ com.android.ide.eclipse.gltrace.GLProtoBuf.internalForceInit();
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage.FrameBuffer)
+ }
+
+ // required int32 context_id = 1;
+ public static final int CONTEXT_ID_FIELD_NUMBER = 1;
+ private boolean hasContextId;
+ private int contextId_ = 0;
+ public boolean hasContextId() { return hasContextId; }
+ public int getContextId() { return contextId_; }
+
+ // required int64 start_time = 2;
+ public static final int START_TIME_FIELD_NUMBER = 2;
+ private boolean hasStartTime;
+ private long startTime_ = 0L;
+ public boolean hasStartTime() { return hasStartTime; }
+ public long getStartTime() { return startTime_; }
+
+ // required int32 duration = 3;
+ public static final int DURATION_FIELD_NUMBER = 3;
+ private boolean hasDuration;
+ private int duration_ = 0;
+ public boolean hasDuration() { return hasDuration; }
+ public int getDuration() { return duration_; }
+
+ // required .android.gltrace.GLMessage.Function function = 4 [default = invalid];
+ public static final int FUNCTION_FIELD_NUMBER = 4;
+ private boolean hasFunction;
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function function_;
+ public boolean hasFunction() { return hasFunction; }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function getFunction() { return function_; }
+
+ // repeated .android.gltrace.GLMessage.DataType args = 5;
+ public static final int ARGS_FIELD_NUMBER = 5;
+ private java.util.List<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType> args_ =
+ java.util.Collections.emptyList();
+ public java.util.List<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType> getArgsList() {
+ return args_;
+ }
+ public int getArgsCount() { return args_.size(); }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType getArgs(int index) {
+ return args_.get(index);
+ }
+
+ // optional .android.gltrace.GLMessage.DataType returnValue = 6;
+ public static final int RETURNVALUE_FIELD_NUMBER = 6;
+ private boolean hasReturnValue;
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType returnValue_;
+ public boolean hasReturnValue() { return hasReturnValue; }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType getReturnValue() { return returnValue_; }
+
+ // optional .android.gltrace.GLMessage.FrameBuffer fb = 7;
+ public static final int FB_FIELD_NUMBER = 7;
+ private boolean hasFb;
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer fb_;
+ public boolean hasFb() { return hasFb; }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer getFb() { return fb_; }
+
+ // optional int32 threadtime = 8;
+ public static final int THREADTIME_FIELD_NUMBER = 8;
+ private boolean hasThreadtime;
+ private int threadtime_ = 0;
+ public boolean hasThreadtime() { return hasThreadtime; }
+ public int getThreadtime() { return threadtime_; }
+
+ private void initFields() {
+ function_ = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function.invalid;
+ returnValue_ = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.getDefaultInstance();
+ fb_ = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.getDefaultInstance();
+ }
+ @Override
+ public final boolean isInitialized() {
+ if (!hasContextId) return false;
+ if (!hasStartTime) return false;
+ if (!hasDuration) return false;
+ if (!hasFunction) return false;
+ for (com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType element : getArgsList()) {
+ if (!element.isInitialized()) return false;
+ }
+ if (hasReturnValue()) {
+ if (!getReturnValue().isInitialized()) return false;
+ }
+ if (hasFb()) {
+ if (!getFb().isInitialized()) return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (hasContextId()) {
+ output.writeInt32(1, getContextId());
+ }
+ if (hasStartTime()) {
+ output.writeInt64(2, getStartTime());
+ }
+ if (hasDuration()) {
+ output.writeInt32(3, getDuration());
+ }
+ if (hasFunction()) {
+ output.writeEnum(4, getFunction().getNumber());
+ }
+ for (com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType element : getArgsList()) {
+ output.writeMessage(5, element);
+ }
+ if (hasReturnValue()) {
+ output.writeMessage(6, getReturnValue());
+ }
+ if (hasFb()) {
+ output.writeMessage(7, getFb());
+ }
+ if (hasThreadtime()) {
+ output.writeInt32(8, getThreadtime());
+ }
+ }
+
+ private int memoizedSerializedSize = -1;
+ @Override
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (hasContextId()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(1, getContextId());
+ }
+ if (hasStartTime()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt64Size(2, getStartTime());
+ }
+ if (hasDuration()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(3, getDuration());
+ }
+ if (hasFunction()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeEnumSize(4, getFunction().getNumber());
+ }
+ for (com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType element : getArgsList()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(5, element);
+ }
+ if (hasReturnValue()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(6, getReturnValue());
+ }
+ if (hasFb()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(7, getFb());
+ }
+ if (hasThreadtime()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(8, getThreadtime());
+ }
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ @Override
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ @Override
+ public Builder toBuilder() { return newBuilder(this); }
+
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessageLite.Builder<
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage, Builder> {
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage result;
+
+ // Construct using com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.newBuilder()
+ private Builder() {}
+
+ private static Builder create() {
+ Builder builder = new Builder();
+ builder.result = new com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage();
+ return builder;
+ }
+
+ @Override
+ protected com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage internalGetResult() {
+ return result;
+ }
+
+ @Override
+ public Builder clear() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "Cannot call clear() after build().");
+ }
+ result = new com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage();
+ return this;
+ }
+
+ @Override
+ public Builder clone() {
+ return create().mergeFrom(result);
+ }
+
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage getDefaultInstanceForType() {
+ return com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.getDefaultInstance();
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return result.isInitialized();
+ }
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage build() {
+ if (result != null && !isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return buildPartial();
+ }
+
+ private com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ if (!isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return buildPartial();
+ }
+
+ @Override
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage buildPartial() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "build() has already been called on this Builder.");
+ }
+ if (result.args_ != java.util.Collections.EMPTY_LIST) {
+ result.args_ =
+ java.util.Collections.unmodifiableList(result.args_);
+ }
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage returnMe = result;
+ result = null;
+ return returnMe;
+ }
+
+ @Override
+ public Builder mergeFrom(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage other) {
+ if (other == com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.getDefaultInstance()) return this;
+ if (other.hasContextId()) {
+ setContextId(other.getContextId());
+ }
+ if (other.hasStartTime()) {
+ setStartTime(other.getStartTime());
+ }
+ if (other.hasDuration()) {
+ setDuration(other.getDuration());
+ }
+ if (other.hasFunction()) {
+ setFunction(other.getFunction());
+ }
+ if (!other.args_.isEmpty()) {
+ if (result.args_.isEmpty()) {
+ result.args_ = new java.util.ArrayList<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType>();
+ }
+ result.args_.addAll(other.args_);
+ }
+ if (other.hasReturnValue()) {
+ mergeReturnValue(other.getReturnValue());
+ }
+ if (other.hasFb()) {
+ mergeFb(other.getFb());
+ }
+ if (other.hasThreadtime()) {
+ setThreadtime(other.getThreadtime());
+ }
+ return this;
+ }
+
+ @Override
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ return this;
+ default: {
+ if (!parseUnknownField(input, extensionRegistry, tag)) {
+ return this;
+ }
+ break;
+ }
+ case 8: {
+ setContextId(input.readInt32());
+ break;
+ }
+ case 16: {
+ setStartTime(input.readInt64());
+ break;
+ }
+ case 24: {
+ setDuration(input.readInt32());
+ break;
+ }
+ case 32: {
+ int rawValue = input.readEnum();
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function value = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function.valueOf(rawValue);
+ if (value != null) {
+ setFunction(value);
+ }
+ break;
+ }
+ case 42: {
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Builder subBuilder = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.newBuilder();
+ input.readMessage(subBuilder, extensionRegistry);
+ addArgs(subBuilder.buildPartial());
+ break;
+ }
+ case 50: {
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Builder subBuilder = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.newBuilder();
+ if (hasReturnValue()) {
+ subBuilder.mergeFrom(getReturnValue());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setReturnValue(subBuilder.buildPartial());
+ break;
+ }
+ case 58: {
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.Builder subBuilder = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.newBuilder();
+ if (hasFb()) {
+ subBuilder.mergeFrom(getFb());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setFb(subBuilder.buildPartial());
+ break;
+ }
+ case 64: {
+ setThreadtime(input.readInt32());
+ break;
+ }
+ }
+ }
+ }
+
+
+ // required int32 context_id = 1;
+ public boolean hasContextId() {
+ return result.hasContextId();
+ }
+ public int getContextId() {
+ return result.getContextId();
+ }
+ public Builder setContextId(int value) {
+ result.hasContextId = true;
+ result.contextId_ = value;
+ return this;
+ }
+ public Builder clearContextId() {
+ result.hasContextId = false;
+ result.contextId_ = 0;
+ return this;
+ }
+
+ // required int64 start_time = 2;
+ public boolean hasStartTime() {
+ return result.hasStartTime();
+ }
+ public long getStartTime() {
+ return result.getStartTime();
+ }
+ public Builder setStartTime(long value) {
+ result.hasStartTime = true;
+ result.startTime_ = value;
+ return this;
+ }
+ public Builder clearStartTime() {
+ result.hasStartTime = false;
+ result.startTime_ = 0L;
+ return this;
+ }
+
+ // required int32 duration = 3;
+ public boolean hasDuration() {
+ return result.hasDuration();
+ }
+ public int getDuration() {
+ return result.getDuration();
+ }
+ public Builder setDuration(int value) {
+ result.hasDuration = true;
+ result.duration_ = value;
+ return this;
+ }
+ public Builder clearDuration() {
+ result.hasDuration = false;
+ result.duration_ = 0;
+ return this;
+ }
+
+ // required .android.gltrace.GLMessage.Function function = 4 [default = invalid];
+ public boolean hasFunction() {
+ return result.hasFunction();
+ }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function getFunction() {
+ return result.getFunction();
+ }
+ public Builder setFunction(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasFunction = true;
+ result.function_ = value;
+ return this;
+ }
+ public Builder clearFunction() {
+ result.hasFunction = false;
+ result.function_ = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function.invalid;
+ return this;
+ }
+
+ // repeated .android.gltrace.GLMessage.DataType args = 5;
+ public java.util.List<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType> getArgsList() {
+ return java.util.Collections.unmodifiableList(result.args_);
+ }
+ public int getArgsCount() {
+ return result.getArgsCount();
+ }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType getArgs(int index) {
+ return result.getArgs(index);
+ }
+ public Builder setArgs(int index, com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.args_.set(index, value);
+ return this;
+ }
+ public Builder setArgs(int index, com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Builder builderForValue) {
+ result.args_.set(index, builderForValue.build());
+ return this;
+ }
+ public Builder addArgs(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ if (result.args_.isEmpty()) {
+ result.args_ = new java.util.ArrayList<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType>();
+ }
+ result.args_.add(value);
+ return this;
+ }
+ public Builder addArgs(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Builder builderForValue) {
+ if (result.args_.isEmpty()) {
+ result.args_ = new java.util.ArrayList<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType>();
+ }
+ result.args_.add(builderForValue.build());
+ return this;
+ }
+ public Builder addAllArgs(
+ java.lang.Iterable<? extends com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType> values) {
+ if (result.args_.isEmpty()) {
+ result.args_ = new java.util.ArrayList<com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType>();
+ }
+ super.addAll(values, result.args_);
+ return this;
+ }
+ public Builder clearArgs() {
+ result.args_ = java.util.Collections.emptyList();
+ return this;
+ }
+
+ // optional .android.gltrace.GLMessage.DataType returnValue = 6;
+ public boolean hasReturnValue() {
+ return result.hasReturnValue();
+ }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType getReturnValue() {
+ return result.getReturnValue();
+ }
+ public Builder setReturnValue(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasReturnValue = true;
+ result.returnValue_ = value;
+ return this;
+ }
+ public Builder setReturnValue(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Builder builderForValue) {
+ result.hasReturnValue = true;
+ result.returnValue_ = builderForValue.build();
+ return this;
+ }
+ public Builder mergeReturnValue(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType value) {
+ if (result.hasReturnValue() &&
+ result.returnValue_ != com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.getDefaultInstance()) {
+ result.returnValue_ =
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.newBuilder(result.returnValue_).mergeFrom(value).buildPartial();
+ } else {
+ result.returnValue_ = value;
+ }
+ result.hasReturnValue = true;
+ return this;
+ }
+ public Builder clearReturnValue() {
+ result.hasReturnValue = false;
+ result.returnValue_ = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.getDefaultInstance();
+ return this;
+ }
+
+ // optional .android.gltrace.GLMessage.FrameBuffer fb = 7;
+ public boolean hasFb() {
+ return result.hasFb();
+ }
+ public com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer getFb() {
+ return result.getFb();
+ }
+ public Builder setFb(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasFb = true;
+ result.fb_ = value;
+ return this;
+ }
+ public Builder setFb(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.Builder builderForValue) {
+ result.hasFb = true;
+ result.fb_ = builderForValue.build();
+ return this;
+ }
+ public Builder mergeFb(com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer value) {
+ if (result.hasFb() &&
+ result.fb_ != com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.getDefaultInstance()) {
+ result.fb_ =
+ com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.newBuilder(result.fb_).mergeFrom(value).buildPartial();
+ } else {
+ result.fb_ = value;
+ }
+ result.hasFb = true;
+ return this;
+ }
+ public Builder clearFb() {
+ result.hasFb = false;
+ result.fb_ = com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.FrameBuffer.getDefaultInstance();
+ return this;
+ }
+
+ // optional int32 threadtime = 8;
+ public boolean hasThreadtime() {
+ return result.hasThreadtime();
+ }
+ public int getThreadtime() {
+ return result.getThreadtime();
+ }
+ public Builder setThreadtime(int value) {
+ result.hasThreadtime = true;
+ result.threadtime_ = value;
+ return this;
+ }
+ public Builder clearThreadtime() {
+ result.hasThreadtime = false;
+ result.threadtime_ = 0;
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:android.gltrace.GLMessage)
+ }
+
+ static {
+ defaultInstance = new GLMessage(true);
+ com.android.ide.eclipse.gltrace.GLProtoBuf.internalForceInit();
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage)
+ }
+
+
+ static {
+ }
+
+ public static void internalForceInit() {}
+
+ // @@protoc_insertion_point(outer_class_scope)
+}
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
new file mode 100644
index 000000000..56dc8e9ac
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceCollectorDialog.java
@@ -0,0 +1,228 @@
+/*
+ * 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 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 java.io.IOException;
+import java.text.DecimalFormat;
+
+/** Dialog displayed while the trace is being streamed from device to host. */
+public class GLTraceCollectorDialog extends TitleAreaDialog {
+ private static final String TITLE = "OpenGL ES Trace";
+ private static final String DEFAULT_MESSAGE = "Trace collection in progress.";
+ private static final DecimalFormat SIZE_FORMATTER = new DecimalFormat("#.##"); //$NON-NLS-1$
+
+ 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
+ protected Control createButtonBar(Composite parent) {
+ Composite c = new Composite(parent, SWT.NONE);
+ c.setLayout(new GridLayout(0, false));
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalAlignment = GridData.CENTER;
+ c.setLayoutData(gd);
+
+ createButton(c, IDialogConstants.OK_ID, "Stop Tracing", true);
+ return c;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ 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());
+ }
+
+ // 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(statusGroup, "Frames Collected:");
+ mFramesCollectedLabel = createLabel(statusGroup, "");
+
+ 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 Button createButton(Composite controlComposite, boolean selection) {
+ Button b = new Button(controlComposite, SWT.TOGGLE);
+ b.setText(getToggleActionText(selection));
+ b.setSelection(selection);
+ return b;
+ }
+
+ /** Get text to show on toggle box given its current selection. */
+ private String getToggleActionText(boolean en) {
+ return en ? "Disable" : "Enable";
+ }
+
+ private Label createLabel(Composite parent, String text) {
+ Label l = new Label(parent, SWT.NONE);
+ l.setText(text);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalAlignment = SWT.LEFT;
+ gd.verticalAlignment = SWT.CENTER;
+ l.setLayoutData(gd);
+
+ return l;
+ }
+
+ @Override
+ protected void okPressed() {
+ mRefreshTask.cancel();
+ super.okPressed();
+ }
+
+ /** Periodically refresh the trace status. */
+ private class StatusRefreshTask implements Runnable {
+ private static final int REFRESH_INTERVAL = 1000;
+ private volatile boolean mIsCancelled = false;
+
+ @Override
+ public void run() {
+ if (mTraceFileWriter == null) {
+ return;
+ }
+
+ while (!mIsCancelled) {
+ final String frameCount = Integer.toString(mTraceFileWriter.getCurrentFrameCount());
+
+ double fileSize = mTraceFileWriter.getCurrentFileSize();
+ fileSize /= (1024 * 1024); // convert to size in MB
+ final String frameSize = SIZE_FORMATTER.format(fileSize) + " MB";
+
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (mFramesCollectedLabel.isDisposed()) {
+ return;
+ }
+
+ mFramesCollectedLabel.setText(frameCount);
+ mTraceFileSizeLabel.setText(frameSize);
+
+ mFramesCollectedLabel.pack();
+ mTraceFileSizeLabel.pack();
+ }
+ });
+
+ try {
+ Thread.sleep(REFRESH_INTERVAL);
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ }
+
+ 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
new file mode 100644
index 000000000..b4de3d151
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java
@@ -0,0 +1,403 @@
+/*
+ * 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 com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.IDevice;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.swt.SWT;
+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;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.prefs.BackingStoreException;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Dialog displaying all the trace options before the user initiates tracing. */
+public class GLTraceOptionsDialog extends TitleAreaDialog {
+ private static final String TITLE = "OpenGL ES Trace Options";
+ private static final String DEFAULT_MESSAGE = "Provide the application and activity to be traced.";
+
+ private static final String PREF_APP_PACKAGE = "gl.trace.apppackage"; //$NON-NLS-1$
+ private static final String PREF_ACTIVITY = "gl.trace.activity"; //$NON-NLS-1$
+ private static final String PREF_TRACEFILE = "gl.trace.destfile"; //$NON-NLS-1$
+ private static final String PREF_DEVICE = "gl.trace.device"; //$NON-NLS-1$
+ private String mLastUsedDevice;
+
+ private static String sSaveToFolder = System.getProperty("user.home"); //$NON-NLS-1$
+
+ private Button mOkButton;
+
+ private Combo mDeviceCombo;
+ private Text mAppPackageToTraceText;
+ private Text mActivityToTraceText;
+ private Button mIsActivityFullyQualifiedButton;
+ private Text mTraceFilePathText;
+
+ private String mSelectedDevice = "";
+ private String mAppPackageToTrace = "";
+ private String mActivityToTrace = "";
+ private String mTraceFilePath = "";
+ private boolean mAllowAppSelection;
+
+ private static boolean sCollectFbOnEglSwap = true;
+ private static boolean sCollectFbOnGlDraw = false;
+ private static boolean sCollectTextureData = false;
+ private static boolean sIsActivityFullyQualified = false;
+ private IDevice[] mDevices;
+
+ public GLTraceOptionsDialog(Shell parentShell) {
+ this(parentShell, true, null);
+ }
+
+ /**
+ * Constructs a dialog displaying options for the tracer.
+ * @param allowAppSelection true if user can change the application to trace
+ * @param appToTrace default application package to trace
+ */
+ public GLTraceOptionsDialog(Shell parentShell, boolean allowAppSelection,
+ String appToTrace) {
+ super(parentShell);
+ loadPreferences();
+
+ mAllowAppSelection = allowAppSelection;
+ if (appToTrace != null) {
+ mAppPackageToTrace = appToTrace;
+ }
+ }
+
+ @Override
+ protected Control createDialogArea(Composite shell) {
+ setTitle(TITLE);
+ setMessage(DEFAULT_MESSAGE);
+
+ Composite parent = (Composite) super.createDialogArea(shell);
+ Composite c = new Composite(parent, SWT.BORDER);
+ c.setLayout(new GridLayout(2, false));
+ c.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ createLabel(c, "Device:");
+ mDevices = AndroidDebugBridge.getBridge().getDevices();
+ createDeviceDropdown(c, mDevices);
+
+ createSeparator(c);
+
+ createLabel(c, "Application Package:");
+ createAppToTraceText(c, "e.g. com.example.package");
+
+ createLabel(c, "Activity to launch:");
+ createActivityToTraceText(c, "Leave blank to launch default activity");
+
+ createLabel(c, "");
+ createIsFullyQualifedActivityButton(c,
+ "Activity name is fully qualified, do not prefix with package name");
+
+ if (!mAllowAppSelection) {
+ mAppPackageToTraceText.setEnabled(false);
+ mActivityToTraceText.setEnabled(false);
+ mIsActivityFullyQualifiedButton.setEnabled(false);
+ }
+
+ createSeparator(c);
+
+ createLabel(c, "Data Collection Options:");
+ createCaptureImageOptions(c);
+
+ createSeparator(c);
+
+ createLabel(c, "Destination File: ");
+ createSaveToField(c);
+
+ return c;
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ super.createButtonsForButtonBar(parent);
+
+ mOkButton = getButton(IDialogConstants.OK_ID);
+ mOkButton.setText("Trace");
+
+ DialogStatus status = validateDialog();
+ mOkButton.setEnabled(status.valid);
+ }
+
+ private void createSeparator(Composite c) {
+ Label l = new Label(c, SWT.SEPARATOR | SWT.HORIZONTAL);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 2;
+ l.setLayoutData(gd);
+ }
+
+ private void createSaveToField(Composite parent) {
+ Composite c = new Composite(parent, SWT.NONE);
+ c.setLayout(new GridLayout(2, false));
+ c.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ mTraceFilePathText = new Text(c, SWT.BORDER);
+ mTraceFilePathText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ mTraceFilePathText.setText(mTraceFilePath);
+ mTraceFilePathText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validateAndSetMessage();
+ }
+ });
+
+ Button browse = new Button(c, SWT.PUSH);
+ browse.setText("Browse...");
+ browse.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ String fName = openBrowseDialog();
+ if (fName == null) {
+ return;
+ }
+
+ mTraceFilePathText.setText(fName);
+ validateAndSetMessage();
+ }
+ });
+ }
+
+ private String openBrowseDialog() {
+ FileDialog fd = new FileDialog(Display.getDefault().getActiveShell(), SWT.SAVE);
+
+ fd.setText("Save To");
+ fd.setFileName("trace1.gltrace");
+
+ fd.setFilterPath(sSaveToFolder);
+ fd.setFilterExtensions(new String[] { "*.gltrace" });
+
+ String fname = fd.open();
+ if (fname == null || fname.trim().length() == 0) {
+ return null;
+ }
+
+ sSaveToFolder = fd.getFilterPath();
+ return fname;
+ }
+
+ /** Options controlling when the FB should be captured. */
+ 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));
+
+ final Button readFbOnEglSwapCheckBox = new Button(c, SWT.CHECK);
+ readFbOnEglSwapCheckBox.setText("Read back framebuffer 0 on eglSwapBuffers()");
+ readFbOnEglSwapCheckBox.setSelection(sCollectFbOnEglSwap);
+
+ final Button readFbOnGlDrawCheckBox = new Button(c, SWT.CHECK);
+ readFbOnGlDrawCheckBox.setText("Read back currently bound framebuffer On glDraw*()");
+ readFbOnGlDrawCheckBox.setSelection(sCollectFbOnGlDraw);
+
+ final Button readTextureDataCheckBox = new Button(c, SWT.CHECK);
+ readTextureDataCheckBox.setText("Collect texture data submitted using glTexImage*()");
+ readTextureDataCheckBox.setSelection(sCollectTextureData);
+
+ SelectionListener l = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ sCollectFbOnEglSwap = readFbOnEglSwapCheckBox.getSelection();
+ sCollectFbOnGlDraw = readFbOnGlDrawCheckBox.getSelection();
+ sCollectTextureData = readTextureDataCheckBox.getSelection();
+ }
+ };
+
+ readFbOnEglSwapCheckBox.addSelectionListener(l);
+ readFbOnGlDrawCheckBox.addSelectionListener(l);
+ readTextureDataCheckBox.addSelectionListener(l);
+ }
+
+ private Text createAppToTraceText(Composite parent, String defaultMessage) {
+ mAppPackageToTraceText = new Text(parent, SWT.BORDER);
+ mAppPackageToTraceText.setMessage(defaultMessage);
+ mAppPackageToTraceText.setText(mAppPackageToTrace);
+
+ mAppPackageToTraceText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ mAppPackageToTraceText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validateAndSetMessage();
+ }
+ });
+
+ return mActivityToTraceText;
+ }
+
+ private Text createActivityToTraceText(Composite parent, String defaultMessage) {
+ mActivityToTraceText = new Text(parent, SWT.BORDER);
+ mActivityToTraceText.setMessage(defaultMessage);
+ mActivityToTraceText.setText(mActivityToTrace);
+
+ mActivityToTraceText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ mActivityToTraceText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validateAndSetMessage();
+ }
+ });
+
+ return mActivityToTraceText;
+ }
+
+ private Button createIsFullyQualifedActivityButton(Composite parent, String message) {
+ mIsActivityFullyQualifiedButton = new Button(parent, SWT.CHECK);
+ mIsActivityFullyQualifiedButton.setText(message);
+ mIsActivityFullyQualifiedButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ mIsActivityFullyQualifiedButton.setSelection(sIsActivityFullyQualified);
+
+ return mIsActivityFullyQualifiedButton;
+ }
+
+ private void validateAndSetMessage() {
+ DialogStatus status = validateDialog();
+ mOkButton.setEnabled(status.valid);
+ setErrorMessage(status.message);
+ }
+
+ private Combo createDeviceDropdown(Composite parent, IDevice[] devices) {
+ mDeviceCombo = new Combo(parent, SWT.READ_ONLY | SWT.BORDER);
+
+ List<String> items = new ArrayList<String>(devices.length);
+ for (IDevice d : devices) {
+ items.add(d.getName());
+ }
+ mDeviceCombo.setItems(items.toArray(new String[items.size()]));
+
+ int index = 0;
+ if (items.contains(mLastUsedDevice)) {
+ index = items.indexOf(mLastUsedDevice);
+ }
+ if (index >= 0 && index < items.size()) {
+ mDeviceCombo.select(index);
+ }
+ return mDeviceCombo;
+ }
+
+ private void createLabel(Composite parent, String text) {
+ Label l = new Label(parent, SWT.NONE);
+ l.setText(text);
+ GridData gd = new GridData();
+ gd.horizontalAlignment = SWT.RIGHT;
+ gd.verticalAlignment = SWT.CENTER;
+ l.setLayoutData(gd);
+ }
+
+ /**
+ * A tuple that specifies whether the current state of the inputs
+ * on the dialog is valid or not. If it is not valid, the message
+ * field stores the reason why it isn't.
+ */
+ private final class DialogStatus {
+ final boolean valid;
+ final String message;
+
+ private DialogStatus(boolean isValid, String errMessage) {
+ valid = isValid;
+ message = errMessage;
+ }
+ }
+
+ private DialogStatus validateDialog() {
+ if (mDevices.length == 0) {
+ return new DialogStatus(false, "No connected devices.");
+ }
+
+ if (mAppPackageToTraceText.getText().trim().isEmpty()) {
+ return new DialogStatus(false, "Provide an application name");
+ }
+
+ String traceFile = mTraceFilePathText.getText().trim();
+ if (traceFile.isEmpty()) {
+ return new DialogStatus(false, "Specify the location where the trace will be saved.");
+ }
+
+ File f = new File(traceFile).getParentFile();
+ if (f != null && !f.exists()) {
+ return new DialogStatus(false,
+ String.format("Folder %s does not exist", f.getAbsolutePath()));
+ }
+
+ return new DialogStatus(true, null);
+ }
+
+ @Override
+ protected void okPressed() {
+ mAppPackageToTrace = mAppPackageToTraceText.getText().trim();
+ mActivityToTrace = mActivityToTraceText.getText().trim();
+ if (mActivityToTrace.startsWith(".")) { //$NON-NLS-1$
+ mActivityToTrace = mActivityToTrace.substring(1);
+ }
+ sIsActivityFullyQualified = mIsActivityFullyQualifiedButton.getSelection();
+ mTraceFilePath = mTraceFilePathText.getText().trim();
+ mSelectedDevice = mDeviceCombo.getText();
+
+ savePreferences();
+
+ super.okPressed();
+ }
+
+ private void savePreferences() {
+ IEclipsePreferences prefs = new InstanceScope().getNode(GlTracePlugin.PLUGIN_ID);
+ prefs.put(PREF_APP_PACKAGE, mAppPackageToTrace);
+ prefs.put(PREF_ACTIVITY, mActivityToTrace);
+ prefs.put(PREF_TRACEFILE, mTraceFilePath);
+ prefs.put(PREF_DEVICE, mSelectedDevice);
+ try {
+ prefs.flush();
+ } catch (BackingStoreException e) {
+ // ignore issues while persisting preferences
+ }
+ }
+
+ private void loadPreferences() {
+ IEclipsePreferences prefs = new InstanceScope().getNode(GlTracePlugin.PLUGIN_ID);
+ mAppPackageToTrace = prefs.get(PREF_APP_PACKAGE, "");
+ mActivityToTrace = prefs.get(PREF_ACTIVITY, "");
+ mTraceFilePath = prefs.get(PREF_TRACEFILE, "");
+ mLastUsedDevice = prefs.get(PREF_DEVICE, "");
+ }
+
+ public TraceOptions getTraceOptions() {
+ return new TraceOptions(mSelectedDevice, mAppPackageToTrace, mActivityToTrace,
+ sIsActivityFullyQualified, mTraceFilePath, sCollectFbOnEglSwap,
+ sCollectFbOnGlDraw, sCollectTextureData);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java
new file mode 100644
index 000000000..30bb1d532
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java
@@ -0,0 +1,56 @@
+/*
+ * 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 com.android.ide.eclipse.gltrace.views.FrameSummaryView;
+import com.android.ide.eclipse.gltrace.views.StateView;
+import com.android.ide.eclipse.gltrace.views.detail.DetailsView;
+
+import org.eclipse.ui.IFolderLayout;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+public class GLTracePerspective implements IPerspectiveFactory {
+ private static final String STATE_FOLDER_ID = "stateFolder"; //$NON-NLS-1$
+ private static final String FB_FOLDER_ID = "fbFolder"; //$NON-NLS-1$
+ private static final String TEXTURE_VIEW_FOLDER_ID = "textureViewFolder"; //$NON-NLS-1$
+
+ @Override
+ public void createInitialLayout(IPageLayout layout) {
+ // Create a 3 column layout
+ // The first column contains the function trace in an editor.
+ // The second column contains the GL State View.
+ // The third column contains the texture view and the top and the framebuffer at the bottom.
+
+ // Add the OpenGL state view to the right of the editor
+ IFolderLayout column2 = layout.createFolder(STATE_FOLDER_ID, IPageLayout.RIGHT, 0.65f,
+ layout.getEditorArea());
+ column2.addView(StateView.ID);
+
+ // Add the Texture View in the 3rd column
+ IFolderLayout column3 = layout.createFolder(FB_FOLDER_ID, IPageLayout.RIGHT, 0.6f,
+ STATE_FOLDER_ID);
+ column3.addView(DetailsView.ID);
+
+ // Add the OpenGL Framebuffer view below the texture view (bottom of 3rd column)
+ IFolderLayout column3bottom = layout.createFolder(TEXTURE_VIEW_FOLDER_ID,
+ IPageLayout.BOTTOM,
+ 0.5f,
+ FB_FOLDER_ID);
+ column3bottom.addView(FrameSummaryView.ID);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLUtils.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLUtils.java
new file mode 100644
index 000000000..9e82768d5
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLUtils.java
@@ -0,0 +1,110 @@
+/*
+ * 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;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+
+public class GLUtils {
+ public static String formatData(byte[] data, GLEnum format) {
+ switch (format) {
+ case GL_BYTE:
+ return formatBytes(data, false);
+ case GL_UNSIGNED_BYTE:
+ return formatBytes(data, true);
+ case GL_SHORT:
+ return formatShorts(data, false);
+ case GL_UNSIGNED_SHORT:
+ return formatShorts(data, true);
+ case GL_FIXED:
+ return formatInts(data);
+ case GL_FLOAT:
+ return formatFloats(data);
+ default:
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ private static String formatFloats(byte[] data) {
+ FloatBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
+
+ StringBuilder sb = new StringBuilder(bb.capacity() * 3);
+
+ while (bb.remaining() > 0) {
+ sb.append(String.format("%.4f", bb.get()));
+ sb.append(',');
+ sb.append('\n');
+ }
+
+ return sb.toString();
+ }
+
+ private static String formatInts(byte[] data) {
+ IntBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
+
+ StringBuilder sb = new StringBuilder(bb.capacity() * 3);
+
+ while (bb.remaining() > 0) {
+ sb.append(bb.get());
+ sb.append(',');
+ sb.append('\n');
+ }
+
+ return sb.toString();
+ }
+
+ private static String formatShorts(byte[] data, boolean unsigned) {
+ ShortBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
+
+ StringBuilder sb = new StringBuilder(bb.capacity() * 3);
+
+ while (bb.remaining() > 0) {
+ if (unsigned) {
+ sb.append(bb.get() & 0xffff);
+ } else {
+ sb.append(bb.get());
+ }
+ sb.append(',');
+ sb.append('\n');
+ }
+
+ return sb.toString();
+ }
+
+ private static String formatBytes(byte[] data, boolean unsigned) {
+ ByteBuffer bb = ByteBuffer.wrap(data);
+
+ StringBuilder sb = new StringBuilder(bb.capacity() * 3);
+
+ while (bb.remaining() > 0) {
+ if (unsigned) {
+ sb.append(bb.get() & 0xff);
+ } else {
+ sb.append(bb.get());
+ }
+
+ sb.append(',');
+ sb.append('\n');
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GlTracePlugin.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GlTracePlugin.java
new file mode 100644
index 000000000..a73b7f18f
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GlTracePlugin.java
@@ -0,0 +1,130 @@
+/*
+ ** Copyright 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 org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.console.ConsolePlugin;
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.IConsoleConstants;
+import org.eclipse.ui.console.MessageConsole;
+import org.eclipse.ui.console.MessageConsoleStream;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class GlTracePlugin extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.android.ide.eclipse.gldebugger"; //$NON-NLS-1$
+
+ // The shared instance
+ private static GlTracePlugin plugin;
+
+ private MessageConsole mConsole;
+ private MessageConsoleStream mConsoleStream;
+
+ /**
+ * The constructor
+ */
+ public GlTracePlugin() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
+ * )
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+
+ mConsole = new MessageConsole("OpenGL Trace View", null);
+ ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] {
+ mConsole });
+
+ mConsoleStream = mConsole.newMessageStream();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
+ * )
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static GlTracePlugin getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Returns an image descriptor for the image file at the given plug-in
+ * relative path
+ *
+ * @param path the path
+ * @return the image descriptor
+ */
+ public static ImageDescriptor getImageDescriptor(String path) {
+ return imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+
+ public void logMessage(String message) {
+ mConsoleStream.println(message);
+
+ Display.getDefault().asyncExec(sShowConsoleRunnable);
+ }
+
+ private static Runnable sShowConsoleRunnable = new Runnable() {
+ @Override
+ public void run() {
+ showConsoleView();
+ };
+ };
+
+ private static void showConsoleView() {
+ IWorkbenchWindow w = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (w != null) {
+ IWorkbenchPage page = w.getActivePage();
+ if (page != null) {
+ try {
+ page.showView(IConsoleConstants.ID_CONSOLE_VIEW, null,
+ IWorkbenchPage.VIEW_VISIBLE);
+ } catch (PartInitException e) {
+ // ignore
+ }
+ }
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/OpenGLTraceAction.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/OpenGLTraceAction.java
new file mode 100644
index 000000000..6e232bb6c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/OpenGLTraceAction.java
@@ -0,0 +1,88 @@
+/*
+ * 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 org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+
+import java.io.File;
+
+public class OpenGLTraceAction implements IWorkbenchWindowActionDelegate {
+ private static String sLoadFromFolder = System.getProperty("user.home");
+
+ @Override
+ public void run(IAction action) {
+ openTrace();
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void init(IWorkbenchWindow window) {
+ }
+
+ private void openTrace() {
+ Shell shell = Display.getDefault().getActiveShell();
+ FileDialog fd = new FileDialog(shell, SWT.OPEN);
+
+ fd.setText("Open Trace File");
+ fd.setFilterPath(sLoadFromFolder);
+ fd.setFilterExtensions(new String[] { "*.gltrace" });
+
+ String fname = fd.open();
+ if (fname == null || fname.trim().length() == 0) {
+ return;
+ }
+
+ sLoadFromFolder = new File(fname).getParent().toString();
+
+ openEditorFor(fname);
+ }
+
+ private void openEditorFor(String fname) {
+ IFileStore fileStore = EFS.getLocalFileSystem().getStore(new Path(fname));
+ IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+
+ try {
+ IDE.openEditorOnFileStore( page, fileStore );
+ } catch (PartInitException e) {
+ MessageDialog.openError(Display.getDefault().getActiveShell(),
+ "Error opening GL Trace File",
+ "Unexpected error while opening GL Trace file: " + e.getMessage());
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/ProtoBufUtils.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/ProtoBufUtils.java
new file mode 100644
index 000000000..074e4409e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/ProtoBufUtils.java
@@ -0,0 +1,86 @@
+/*
+ * 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 com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.widgets.Display;
+import org.liblzf.CLZF;
+
+/** Utilities to deal with protobuf encoded {@link GLMessage}. */
+public class ProtoBufUtils {
+ private static ImageData getImageData(GLMessage glMsg) {
+ int width = glMsg.getFb().getWidth();
+ int height = glMsg.getFb().getHeight();
+
+ if (width * height == 0) {
+ return null;
+ }
+
+ byte[] compressed = glMsg.getFb().getContents(0).toByteArray();
+ byte[] uncompressed = new byte[width * height * 4];
+
+ int size = CLZF.lzf_decompress(compressed, compressed.length,
+ uncompressed, uncompressed.length);
+ assert size == width * height * 4 : "Unexpected image size after decompression.";
+
+ int redMask = 0xff000000;
+ int greenMask = 0x00ff0000;
+ int blueMask = 0x0000ff00;
+ PaletteData palette = new PaletteData(redMask, greenMask, blueMask);
+ ImageData imageData = new ImageData(
+ width,
+ height,
+ 32, // depth
+ palette,
+ 1, // scan line padding
+ uncompressed);
+ byte[] alpha = new byte[width*height];
+ for (int i = 0; i < width * height; i++) {
+ alpha[i] = uncompressed[i * 4 + 3];
+ }
+ imageData.alphaData = alpha;
+
+ imageData = imageData.scaledTo(imageData.width, -imageData.height);
+ return imageData;
+ }
+
+ /** Obtains the image stored in provided protocol buffer message. */
+ public static Image getImage(Display display, GLMessage glMsg) {
+ if (!glMsg.hasFb()) {
+ return null;
+ }
+
+ ImageData imageData = null;
+ try {
+ imageData = getImageData(glMsg);
+ } catch (Exception e) {
+ GlTracePlugin.getDefault().logMessage(
+ "Unexpected error while retrieving framebuffer image: " + e);
+ return null;
+ }
+
+ if (imageData == null) {
+ return null;
+ }
+
+ return new Image(display, imageData);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/SwtUtils.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/SwtUtils.java
new file mode 100644
index 000000000..a7c960dfc
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/SwtUtils.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.widgets.Control;
+
+public class SwtUtils {
+ /** Minimum Character width in pixels. */
+ private static final int MIN_CHAR_WIDTH = 10;
+
+ /** Returns the font width if it is greater than {@link #MIN_CHAR_WIDTH}. */
+ public static int getApproximateFontWidth(Control c) {
+ GC gc = new GC(c);
+ int avgCharWidth = gc.getFontMetrics().getAverageCharWidth();
+ gc.dispose();
+ return Math.max(avgCharWidth, MIN_CHAR_WIDTH);
+ }
+}
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 000000000..dd5cd3c1e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceCommandWriter.java
@@ -0,0 +1,60 @@
+/*
+ * 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 CMD_SIZE = 4;
+
+ 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_SIZE);
+ 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/TraceFileInfo.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileInfo.java
new file mode 100644
index 000000000..80933b02e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileInfo.java
@@ -0,0 +1,41 @@
+/*
+ * 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 TraceFileInfo {
+ private final String mPath;
+ private final long mSize;
+ private final long mLastModified;
+
+ public TraceFileInfo(String path, long size, long lastModified) {
+ mPath = path;
+ mSize = size;
+ mLastModified = lastModified;
+ }
+
+ public String getPath() {
+ return mPath;
+ }
+
+ public long getSize() {
+ return mSize;
+ }
+
+ public long getLastModificationTime() {
+ return mLastModified;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java
new file mode 100644
index 000000000..b90c004b0
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileParserTask.java
@@ -0,0 +1,254 @@
+/*
+ * 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 com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage;
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function;
+import com.android.ide.eclipse.gltrace.format.GLAPISpec;
+import com.android.ide.eclipse.gltrace.format.GLMessageFormatter;
+import com.android.ide.eclipse.gltrace.model.GLCall;
+import com.android.ide.eclipse.gltrace.model.GLFrame;
+import com.android.ide.eclipse.gltrace.model.GLTrace;
+import com.android.ide.eclipse.gltrace.state.transforms.StateTransformFactory;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class TraceFileParserTask implements IRunnableWithProgress {
+ private static final TraceFileReader sReader = new TraceFileReader();
+
+ private static final GLMessageFormatter sGLMessageFormatter =
+ new GLMessageFormatter(GLAPISpec.getSpecs());
+
+ private String mTraceFilePath;
+ private RandomAccessFile mFile;
+
+ private List<GLCall> mGLCalls;
+ private Set<Integer> mGLContextIds;
+
+ private GLTrace mTrace;
+
+ /**
+ * Construct a GL Trace file parser.
+ * @param path path to trace file
+ */
+ public TraceFileParserTask(String path) {
+ try {
+ mFile = new RandomAccessFile(path, "r"); //$NON-NLS-1$
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ mTraceFilePath = path;
+ mGLCalls = new ArrayList<GLCall>();
+ mGLContextIds = new TreeSet<Integer>();
+ }
+
+ private void addMessage(int index, long traceFileOffset, GLMessage msg, long startTime) {
+ String formattedMsg;
+ try {
+ formattedMsg = sGLMessageFormatter.formatGLMessage(msg);
+ } catch (Exception e) {
+ formattedMsg = String.format("%s()", msg.getFunction().toString()); //$NON-NLS-1$
+ }
+
+ GLCall c = new GLCall(index,
+ startTime,
+ traceFileOffset,
+ formattedMsg,
+ msg.getFunction(),
+ msg.hasFb(),
+ msg.getContextId(),
+ msg.getDuration(),
+ msg.getThreadtime());
+
+ addProperties(c, msg);
+
+ try {
+ c.setStateTransformations(StateTransformFactory.getTransformsFor(msg));
+ } catch (Exception e) {
+ c.setStateTransformationCreationError(e.getMessage());
+ GlTracePlugin.getDefault().logMessage("Error while creating transformations for "
+ + c.toString() + ":");
+ GlTracePlugin.getDefault().logMessage(e.getMessage());
+ }
+
+ mGLCalls.add(c);
+ mGLContextIds.add(Integer.valueOf(c.getContextId()));
+ }
+
+ /** Save important values from the {@link GLMessage} in the {@link GLCall} as properties. */
+ private void addProperties(GLCall c, GLMessage msg) {
+ switch (msg.getFunction()) {
+ case glPushGroupMarkerEXT:
+ // void PushGroupMarkerEXT(sizei length, const char *marker);
+ // save the marker name
+ c.addProperty(GLCall.PROPERTY_MARKERNAME,
+ msg.getArgs(1).getCharValue(0).toStringUtf8());
+ break;
+ case glVertexAttribPointerData:
+ // void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type,
+ // GLboolean normalized, GLsizei stride, const GLvoid* ptr,
+ // int minIndex, int maxIndex)
+ c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_SIZE,
+ Integer.valueOf(msg.getArgs(1).getIntValue(0)));
+ c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_TYPE,
+ GLEnum.valueOf(msg.getArgs(2).getIntValue(0)));
+ c.addProperty(GLCall.PROPERTY_VERTEX_ATTRIB_POINTER_DATA,
+ msg.getArgs(5).getRawBytes(0).toByteArray());
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Parse the entire file and create a {@link GLTrace} object that can be retrieved
+ * using {@link #getTrace()}.
+ */
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException,
+ InterruptedException {
+ long fileLength;
+ try {
+ fileLength = mFile.length();
+ } catch (IOException e1) {
+ fileLength = 0;
+ }
+
+ monitor.beginTask("Parsing OpenGL Trace File",
+ fileLength > 0 ? 100 : IProgressMonitor.UNKNOWN);
+
+ List<GLFrame> glFrames = null;
+
+ try {
+ GLMessage msg = null;
+ int msgCount = 0;
+ long filePointer = mFile.getFilePointer();
+ int percentParsed = 0;
+
+ // counters that maintain some statistics about the trace messages
+ long minTraceStartTime = Long.MAX_VALUE;
+
+ while ((msg = sReader.getMessageAtOffset(mFile, -1)) != null) {
+ if (minTraceStartTime > msg.getStartTime()) {
+ minTraceStartTime = msg.getStartTime();
+ }
+
+ addMessage(msgCount, filePointer, msg, msg.getStartTime() - minTraceStartTime);
+
+ filePointer = mFile.getFilePointer();
+ msgCount++;
+
+ if (monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ if (fileLength > 0) {
+ int percentParsedNow = (int)((filePointer * 100) / fileLength);
+ monitor.worked(percentParsedNow - percentParsed);
+ percentParsed = percentParsedNow;
+ }
+ }
+
+ if (mGLContextIds.size() > 1) {
+ // if there are multiple contexts, then the calls may arrive at the
+ // host out of order. So we perform a sort based on the invocation time.
+ Collections.sort(mGLCalls, new Comparator<GLCall>() {
+ @Override
+ public int compare(GLCall c1, GLCall c2) {
+ long diff = (c1.getStartTime() - c2.getStartTime());
+
+ // We could return diff casted to an int. But in Java, casting
+ // from a long to an int truncates the bits and will not preserve
+ // the sign. So we resort to comparing the diff to 0 and returning
+ // the sign.
+ if (diff == 0) {
+ return 0;
+ } else if (diff > 0) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ });
+
+ // reassign indices after sorting
+ for (int i = 0; i < mGLCalls.size(); i++) {
+ mGLCalls.get(i).setIndex(i);
+ }
+ }
+
+ glFrames = createFrames(mGLCalls);
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ } finally {
+ try {
+ mFile.close();
+ } catch (IOException e) {
+ // ignore exception while closing file
+ }
+ monitor.done();
+ }
+
+ File f = new File(mTraceFilePath);
+ TraceFileInfo fileInfo = new TraceFileInfo(mTraceFilePath, f.length(), f.lastModified());
+ mTrace = new GLTrace(fileInfo, glFrames, mGLCalls, new ArrayList<Integer>(mGLContextIds));
+ }
+
+ /** Assign GL calls to GL Frames. */
+ private List<GLFrame> createFrames(List<GLCall> calls) {
+ List<GLFrame> glFrames = new ArrayList<GLFrame>();
+ int startCallIndex = 0;
+ int frameIndex = 0;
+
+ for (int i = 0; i < calls.size(); i++) {
+ GLCall c = calls.get(i);
+ if (c.getFunction() == Function.eglSwapBuffers) {
+ glFrames.add(new GLFrame(frameIndex, startCallIndex, i + 1));
+ startCallIndex = i + 1;
+ frameIndex++;
+ }
+ }
+
+ // assign left over calls at the end to the last frame
+ if (startCallIndex != mGLCalls.size()) {
+ glFrames.add(new GLFrame(frameIndex, startCallIndex, mGLCalls.size()));
+ }
+
+ return glFrames;
+ }
+
+ /**
+ * Retrieve the trace object constructed from messages in the trace file.
+ */
+ public GLTrace getTrace() {
+ return mTrace;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileReader.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileReader.java
new file mode 100644
index 000000000..76b32b099
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileReader.java
@@ -0,0 +1,66 @@
+/*
+ * 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 com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+public class TraceFileReader {
+ /** Maximum size for a protocol buffer message.
+ * The message size is dominated by the size of the compressed framebuffer.
+ * Currently, we assume that the maximum is for a 1080p display. Since the buffers compress
+ * well, we should probably never get close to this.
+ */
+ private static final int MAX_PROTOBUF_SIZE = 1920 * 1080 * 100;
+
+ /**
+ * Obtain the next protobuf message in this file.
+ * @param file file to read from
+ * @param offset offset to start reading from
+ * @return protobuf message at given offset
+ * @throws IOException in case of file I/O errors
+ * @throws InvalidProtocolBufferException if protobuf is not well formed
+ */
+ public GLMessage getMessageAtOffset(RandomAccessFile file, long offset) throws IOException {
+ int len;
+ byte[] b;
+ try {
+ if (offset != -1) {
+ file.seek(offset);
+ }
+
+ len = file.readInt();
+ if (len > MAX_PROTOBUF_SIZE) {
+ String msg = String.format(
+ "Unexpectedly large (%d bytes) protocol buffer message encountered.",
+ len);
+ throw new InvalidProtocolBufferException(msg);
+ }
+
+ b = new byte[len];
+ file.readFully(b);
+ } catch (EOFException e) {
+ return null;
+ }
+
+ return GLMessage.parseFrom(b);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileWriter.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileWriter.java
new file mode 100644
index 000000000..0be05aee2
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceFileWriter.java
@@ -0,0 +1,156 @@
+/*
+ * 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 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;
+
+/** A class that streams data received from a socket into the trace file. */
+public class TraceFileWriter {
+ private DataInputStream mInputStream;
+ private DataOutputStream mOutputStream;
+ private Thread mReceiverThread;
+
+ private int mFileSize = 0;
+ private int mFrameCount = 0;
+
+ /**
+ * 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);
+ mInputStream = is;
+ }
+
+ public void start() {
+ // launch thread
+ mReceiverThread = new Thread(new GLTraceReceiverTask());
+ mReceiverThread.setName("GL Trace Receiver");
+ mReceiverThread.start();
+ }
+
+ public void stopTracing() {
+ // close socket to stop the receiver thread
+ try {
+ mInputStream.close();
+ } catch (IOException e) {
+ // ignore exception while closing socket
+ }
+
+ // wait for receiver to complete
+ try {
+ mReceiverThread.join();
+ } catch (InterruptedException e1) {
+ // ignore, this cannot be interrupted
+ }
+
+ // close stream
+ try {
+ mOutputStream.close();
+ } catch (IOException e) {
+ // ignore error while closing stream
+ }
+ }
+
+ /**
+ * 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 {
+ @Override
+ public void run() {
+ while (true) {
+ byte[] buffer = readTraceData(mInputStream);
+ if (buffer == null) {
+ break;
+ }
+
+ try {
+ writeTraceData(buffer, mOutputStream);
+ } catch (IOException e) {
+ break;
+ }
+
+ updateTraceStats(buffer);
+ }
+ }
+ }
+
+ 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) {
+ 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) {
+ return;
+ }
+
+ mFileSize += buffer.length;
+
+ 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 000000000..ac9fb6b5c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+ /** Application to trace. */
+ public final String appToTrace;
+
+ /** Activity to trace. */
+ public final String activityToTrace;
+
+ public final boolean isActivityNameFullyQualified;
+
+ /** 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 appPackage, String activity,
+ boolean isActivityNameFullyQualified, String destinationPath,
+ boolean collectFbOnEglSwap, boolean collectFbOnGlDraw, boolean collectTextureData) {
+ this.device = device;
+ this.appToTrace = appPackage;
+ this.activityToTrace = activity;
+ this.isActivityNameFullyQualified = isActivityNameFullyQualified;
+ 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/DurationMinimap.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/DurationMinimap.java
new file mode 100644
index 000000000..9b4c57cad
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/DurationMinimap.java
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.gltrace.editors;
+
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function;
+import com.android.ide.eclipse.gltrace.model.GLCall;
+import com.android.ide.eclipse.gltrace.model.GLTrace;
+
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DurationMinimap extends Canvas {
+ /** Default alpha value. */
+ private static final int DEFAULT_ALPHA = 255;
+
+ /** Alpha value for highlighting visible calls. */
+ private static final int VISIBLE_CALLS_HIGHLIGHT_ALPHA = 50;
+
+ /** Clamp call durations at this value. */
+ private static final long CALL_DURATION_CLAMP = 20000;
+
+ private static final String FONT_KEY = "default.font"; //$NON-NLS-1$
+
+ /** Scale font size by this amount to get the max display length of call duration. */
+ private static final int MAX_DURATION_LENGTH_SCALE = 6;
+
+ /** List of GL Calls in the trace. */
+ private List<GLCall> mCalls;
+
+ /** Number of GL contexts in the trace. */
+ private int mContextCount;
+
+ /** Starting call index of currently displayed frame. */
+ private int mStartCallIndex;
+
+ /** Ending call index of currently displayed frame. */
+ private int mEndCallIndex;
+
+ /** The top index that is currently visible in the table. */
+ private int mVisibleCallTopIndex;
+
+ /** The bottom index that is currently visible in the table. */
+ private int mVisibleCallBottomIndex;
+
+ private Color mBackgroundColor;
+ private Color mDurationLineColor;
+ private Color mGlDrawColor;
+ private Color mGlErrorColor;
+ private Color mContextHeaderColor;
+ private Color mVisibleCallsHighlightColor;
+ private Color mMouseMarkerColor;
+
+ private FontRegistry mFontRegistry;
+ private int mFontWidth;
+ private int mFontHeight;
+
+ // back buffers used for double buffering
+ private Image mBackBufferImage;
+ private GC mBackBufferGC;
+
+ // mouse state
+ private boolean mMouseInSelf;
+ private int mMouseY;
+
+ // helper object used to position various items on screen
+ private final PositionHelper mPositionHelper;
+
+ public DurationMinimap(Composite parent, GLTrace trace) {
+ super(parent, SWT.NO_BACKGROUND);
+
+ setInput(trace);
+
+ initializeColors();
+ initializeFonts();
+
+ mPositionHelper = new PositionHelper(
+ mFontHeight,
+ mContextCount,
+ mFontWidth * MAX_DURATION_LENGTH_SCALE, /* max display length for call. */
+ CALL_DURATION_CLAMP /* max duration */);
+
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ draw(e.display, e.gc);
+ }
+ });
+
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ controlResized();
+ }
+ });
+
+ addMouseMoveListener(new MouseMoveListener() {
+ @Override
+ public void mouseMove(MouseEvent e) {
+ mouseMoved(e);
+ }
+ });
+
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent e) {
+ mouseClicked(e);
+ }
+ });
+
+ addMouseTrackListener(new MouseTrackListener() {
+ @Override
+ public void mouseHover(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseExit(MouseEvent e) {
+ mMouseInSelf = false;
+ redraw();
+ }
+
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ mMouseInSelf = true;
+ redraw();
+ }
+ });
+ }
+
+ public void setInput(GLTrace trace) {
+ if (trace != null) {
+ mCalls = trace.getGLCalls();
+ mContextCount = trace.getContexts().size();
+ } else {
+ mCalls = null;
+ mContextCount = 1;
+ }
+ }
+
+ @Override
+ public void dispose() {
+ disposeColors();
+ disposeBackBuffer();
+ super.dispose();
+ }
+
+ private void initializeColors() {
+ mBackgroundColor = new Color(getDisplay(), 0x33, 0x33, 0x33);
+ mDurationLineColor = new Color(getDisplay(), 0x08, 0x51, 0x9c);
+ mGlDrawColor = new Color(getDisplay(), 0x6b, 0xae, 0xd6);
+ mContextHeaderColor = new Color(getDisplay(), 0xd1, 0xe5, 0xf0);
+ mVisibleCallsHighlightColor = new Color(getDisplay(), 0xcc, 0xcc, 0xcc);
+ mMouseMarkerColor = new Color(getDisplay(), 0xaa, 0xaa, 0xaa);
+
+ mGlErrorColor = getDisplay().getSystemColor(SWT.COLOR_RED);
+ }
+
+ private void disposeColors() {
+ mBackgroundColor.dispose();
+ mDurationLineColor.dispose();
+ mGlDrawColor.dispose();
+ mContextHeaderColor.dispose();
+ mVisibleCallsHighlightColor.dispose();
+ mMouseMarkerColor.dispose();
+ }
+
+ private void initializeFonts() {
+ mFontRegistry = new FontRegistry(getDisplay());
+ mFontRegistry.put(FONT_KEY,
+ new FontData[] { new FontData("Arial", 8, SWT.NORMAL) }); //$NON-NLS-1$
+
+ GC gc = new GC(getDisplay());
+ gc.setFont(mFontRegistry.get(FONT_KEY));
+ mFontWidth = gc.getFontMetrics().getAverageCharWidth();
+ mFontHeight = gc.getFontMetrics().getHeight();
+ gc.dispose();
+ }
+
+ private void initializeBackBuffer() {
+ Rectangle clientArea = getClientArea();
+
+ if (clientArea.width == 0 || clientArea.height == 0) {
+ mBackBufferImage = null;
+ mBackBufferGC = null;
+ return;
+ }
+
+ mBackBufferImage = new Image(getDisplay(),
+ clientArea.width,
+ clientArea.height);
+ mBackBufferGC = new GC(mBackBufferImage);
+ }
+
+ private void disposeBackBuffer() {
+ if (mBackBufferImage != null) {
+ mBackBufferImage.dispose();
+ mBackBufferImage = null;
+ }
+
+ if (mBackBufferGC != null) {
+ mBackBufferGC.dispose();
+ mBackBufferGC = null;
+ }
+ }
+
+ private void mouseMoved(MouseEvent e) {
+ mMouseY = e.y;
+ redraw();
+ }
+
+ private void mouseClicked(MouseEvent e) {
+ if (mMouseInSelf) {
+ int selIndex = mPositionHelper.getCallAt(mMouseY);
+ sendCallSelectedEvent(selIndex);
+ redraw();
+ }
+ }
+
+ private void draw(Display display, GC gc) {
+ if (mBackBufferImage == null) {
+ initializeBackBuffer();
+ }
+
+ if (mBackBufferImage == null) {
+ return;
+ }
+
+ // draw contents onto the back buffer
+ drawBackground(mBackBufferGC, mBackBufferImage.getBounds());
+ drawContextHeaders(mBackBufferGC);
+ drawCallDurations(mBackBufferGC);
+ drawVisibleCallHighlights(mBackBufferGC);
+ drawMouseMarkers(mBackBufferGC);
+
+ // finally copy over the rendered back buffer onto screen
+ int width = getClientArea().width;
+ int height = getClientArea().height;
+ gc.drawImage(mBackBufferImage,
+ 0, 0, width, height,
+ 0, 0, width, height);
+ }
+
+ private void drawBackground(GC gc, Rectangle bounds) {
+ gc.setBackground(mBackgroundColor);
+ gc.fillRectangle(bounds);
+ }
+
+ private void drawContextHeaders(GC gc) {
+ if (mContextCount <= 1) {
+ return;
+ }
+
+ gc.setForeground(mContextHeaderColor);
+ gc.setFont(mFontRegistry.get(FONT_KEY));
+ for (int i = 0; i < mContextCount; i++) {
+ Point p = mPositionHelper.getHeaderLocation(i);
+ gc.drawText("CTX" + Integer.toString(i), p.x, p.y);
+ }
+ }
+
+ /** Draw the call durations as a sequence of lines.
+ *
+ * Calls are arranged on the y-axis based on the sequence in which they were originally
+ * called by the application. If the display height is lesser than the number of calls, then
+ * not every call is shown - the calls are underscanned based the height of the display.
+ *
+ * The x-axis shows two pieces of information: the duration of the call, and the context
+ * in which the call was made. The duration controls how long the displayed line is, and
+ * the context controls the starting offset of the line.
+ */
+ private void drawCallDurations(GC gc) {
+ if (mCalls == null || mCalls.size() < mEndCallIndex) {
+ return;
+ }
+
+ gc.setBackground(mDurationLineColor);
+
+ int callUnderScan = mPositionHelper.getCallUnderScanValue();
+ for (int i = mStartCallIndex; i < mEndCallIndex; i += callUnderScan) {
+ boolean resetColor = false;
+ GLCall c = mCalls.get(i);
+
+ long duration = c.getWallDuration();
+
+ if (c.hasErrors()) {
+ gc.setBackground(mGlErrorColor);
+ resetColor = true;
+
+ // If the call has any errors, we want it to be visible in the minimap
+ // regardless of how long it took.
+ duration = mPositionHelper.getMaxDuration();
+ } else if (c.getFunction() == Function.glDrawArrays
+ || c.getFunction() == Function.glDrawElements
+ || c.getFunction() == Function.eglSwapBuffers) {
+ gc.setBackground(mGlDrawColor);
+ resetColor = true;
+
+ // render all draw calls & swap buffer at max length
+ duration = mPositionHelper.getMaxDuration();
+ }
+
+ Rectangle bounds = mPositionHelper.getDurationBounds(
+ i - mStartCallIndex,
+ c.getContextId(),
+ duration);
+ gc.fillRectangle(bounds);
+
+ if (resetColor) {
+ gc.setBackground(mDurationLineColor);
+ }
+ }
+ }
+
+ /**
+ * Draw a bounding box that highlights the currently visible range of calls in the
+ * {@link GLFunctionTraceViewer} table.
+ */
+ private void drawVisibleCallHighlights(GC gc) {
+ gc.setAlpha(VISIBLE_CALLS_HIGHLIGHT_ALPHA);
+ gc.setBackground(mVisibleCallsHighlightColor);
+ gc.fillRectangle(mPositionHelper.getBoundsFramingCalls(
+ mVisibleCallTopIndex - mStartCallIndex,
+ mVisibleCallBottomIndex - mStartCallIndex));
+ gc.setAlpha(DEFAULT_ALPHA);
+ }
+
+ private void drawMouseMarkers(GC gc) {
+ if (!mMouseInSelf) {
+ return;
+ }
+
+ if (mPositionHelper.getCallAt(mMouseY) < 0) {
+ return;
+ }
+
+ gc.setForeground(mMouseMarkerColor);
+ gc.drawLine(0, mMouseY, getClientArea().width, mMouseY);
+ }
+
+ private void controlResized() {
+ // regenerate back buffer on size changes
+ disposeBackBuffer();
+ initializeBackBuffer();
+
+ redraw();
+ }
+
+ public int getMinimumWidth() {
+ return mPositionHelper.getMinimumWidth();
+ }
+
+ /** Set the GL Call start and end indices for currently displayed frame. */
+ public void setCallRangeForCurrentFrame(int startCallIndex, int endCallIndex) {
+ mStartCallIndex = startCallIndex;
+ mEndCallIndex = endCallIndex;
+ mPositionHelper.updateCallDensity(mEndCallIndex - mStartCallIndex, getClientArea().height);
+ redraw();
+ }
+
+ /**
+ * Set the call range that is currently visible in the {@link GLFunctionTraceViewer} table.
+ * @param visibleTopIndex index of call currently visible at the top of the table.
+ * @param visibleBottomIndex index of call currently visible at the bottom of the table.
+ */
+ public void setVisibleCallRange(int visibleTopIndex, int visibleBottomIndex) {
+ mVisibleCallTopIndex = visibleTopIndex;
+ mVisibleCallBottomIndex = visibleBottomIndex;
+ redraw();
+ }
+
+ public interface ICallSelectionListener {
+ void callSelected(int selectedCallIndex);
+ }
+
+ private List<ICallSelectionListener> mListeners = new ArrayList<ICallSelectionListener>();
+
+ public void addCallSelectionListener(ICallSelectionListener l) {
+ mListeners.add(l);
+ }
+
+ private void sendCallSelectedEvent(int selectedCall) {
+ for (ICallSelectionListener l : mListeners) {
+ l.callSelected(selectedCall);
+ }
+ }
+
+ /** Utility class to help with the positioning and sizes of elements in the canvas. */
+ private static class PositionHelper {
+ /** Left Margin after which duration lines are drawn. */
+ private static final int LEFT_MARGIN = 5;
+
+ /** Top margin after which header is drawn. */
+ private static final int TOP_MARGIN = 5;
+
+ /** # of pixels of padding between duration markers for different contexts. */
+ private static final int CONTEXT_PADDING = 10;
+
+ private final int mHeaderMargin;
+ private final int mContextCount;
+ private final int mMaxDurationLength;
+ private final long mMaxDuration;
+ private final double mScale;
+
+ private int mCallCount;
+ private int mNumCallsPerPixel = 1;
+
+ public PositionHelper(int fontHeight, int contextCount,
+ int maxDurationLength, long maxDuration) {
+ mContextCount = contextCount;
+ mMaxDurationLength = maxDurationLength;
+ mMaxDuration = maxDuration;
+ mScale = (double) maxDurationLength / maxDuration;
+
+ // header region is present only there are multiple contexts
+ if (mContextCount > 1) {
+ mHeaderMargin = fontHeight * 3;
+ } else {
+ mHeaderMargin = 0;
+ }
+ }
+
+ /** Get the minimum width of the canvas. */
+ public int getMinimumWidth() {
+ return LEFT_MARGIN + (mMaxDurationLength + CONTEXT_PADDING) * mContextCount;
+ }
+
+ /** Get the bounds for a call duration line. */
+ public Rectangle getDurationBounds(int callIndex, int context, long duration) {
+ if (duration <= 0) {
+ duration = 1;
+ } else if (duration > mMaxDuration) {
+ duration = mMaxDuration;
+ }
+
+ int x = LEFT_MARGIN + ((mMaxDurationLength + CONTEXT_PADDING) * context);
+ int y = (callIndex/mNumCallsPerPixel) + TOP_MARGIN + mHeaderMargin;
+ int w = (int) (duration * mScale);
+ int h = 1;
+
+ return new Rectangle(x, y, w, h);
+ }
+
+ public long getMaxDuration() {
+ return mMaxDuration;
+ }
+
+ /** Get the bounds for calls spanning given range. */
+ public Rectangle getBoundsFramingCalls(int startCallIndex, int endCallIndex) {
+ if (startCallIndex >= 0 && endCallIndex >= startCallIndex
+ && endCallIndex <= mCallCount) {
+ int x = LEFT_MARGIN;
+ int y = (startCallIndex/mNumCallsPerPixel) + TOP_MARGIN + mHeaderMargin;
+ int w = ((mMaxDurationLength + CONTEXT_PADDING) * mContextCount);
+ int h = (endCallIndex - startCallIndex)/mNumCallsPerPixel;
+ return new Rectangle(x, y, w, h);
+ } else {
+ return new Rectangle(0, 0, 0, 0);
+ }
+ }
+
+ public Point getHeaderLocation(int context) {
+ int x = LEFT_MARGIN + ((mMaxDurationLength + CONTEXT_PADDING) * context);
+ return new Point(x, TOP_MARGIN);
+ }
+
+ /** Update the call density based on the number of calls to be displayed and
+ * the available height to display them in. */
+ public void updateCallDensity(int callCount, int displayHeight) {
+ mCallCount = callCount;
+
+ if (displayHeight <= 0) {
+ displayHeight = callCount + 1;
+ }
+
+ mNumCallsPerPixel = (callCount / displayHeight) + 1;
+ }
+
+ /** Get the underscan value. In cases where there are more calls to be displayed
+ * than there are availble pixels, we only display 1 out of every underscan calls. */
+ public int getCallUnderScanValue() {
+ return mNumCallsPerPixel;
+ }
+
+ /** Get the index of the call at given y offset. */
+ public int getCallAt(int y) {
+ if (!isWithinBounds(y)) {
+ return -1;
+ }
+
+ Rectangle displayBounds = getBoundsFramingCalls(0, mCallCount);
+ return (y - displayBounds.y) * mNumCallsPerPixel;
+ }
+
+ /** Does the provided y offset map to a valid call? */
+ private boolean isWithinBounds(int y) {
+ Rectangle displayBounds = getBoundsFramingCalls(0, mCallCount);
+ if (y < displayBounds.y) {
+ return false;
+ }
+
+ if (y > (displayBounds.y + displayBounds.height)) {
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java
new file mode 100644
index 000000000..226d4831a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLCallGroups.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.gltrace.editors;
+
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function;
+import com.android.ide.eclipse.gltrace.model.GLCall;
+import com.android.ide.eclipse.gltrace.model.GLTrace;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Stack;
+
+public class GLCallGroups {
+ /**
+ * A {@link GLCallNode} is a simple wrapper around a {@link GLCall} that
+ * adds the notion of hierarchy.
+ */
+ public interface GLCallNode {
+ /** Does this call have child nodes? */
+ boolean hasChildren();
+
+ /** Returns a list of child nodes of this call. */
+ List<GLCallNode> getChildren();
+
+ /** Returns the {@link GLCall} that is wrapped by this node. */
+ GLCall getCall();
+
+ /** Returns the parent of this node, the parent is null if this is a top level node */
+ GLCallNode getParent();
+
+ /** Set the parent node. */
+ void setParent(GLCallNode parent);
+ }
+
+ private static class GLTreeNode implements GLCallNode {
+ private final GLCall mCall;
+ private GLCallNode mParent;
+ private List<GLCallNode> mGLCallNodes;
+
+ public GLTreeNode(GLCall call) {
+ mCall = call;
+ mGLCallNodes = new ArrayList<GLCallNode>();
+ }
+
+ @Override
+ public boolean hasChildren() {
+ return true;
+ }
+
+ @Override
+ public GLCallNode getParent() {
+ return mParent;
+ }
+
+ @Override
+ public void setParent(GLCallNode parent) {
+ mParent = parent;
+ }
+
+ @Override
+ public List<GLCallNode> getChildren() {
+ return mGLCallNodes;
+ }
+
+ public void addChild(GLCallNode n) {
+ mGLCallNodes.add(n);
+ n.setParent(this);
+ }
+
+ @Override
+ public GLCall getCall() {
+ return mCall;
+ }
+ }
+
+ private static class GLLeafNode implements GLCallNode {
+ private final GLCall mCall;
+ private GLCallNode mParent;
+
+ public GLLeafNode(GLCall call) {
+ mCall = call;
+ }
+
+ @Override
+ public boolean hasChildren() {
+ return false;
+ }
+
+ @Override
+ public List<GLCallNode> getChildren() {
+ return null;
+ }
+
+ @Override
+ public GLCallNode getParent() {
+ return mParent;
+ }
+
+ @Override
+ public void setParent(GLCallNode parent) {
+ mParent = parent;
+ }
+
+ @Override
+ public GLCall getCall() {
+ return mCall;
+ }
+ }
+
+ /**
+ * Impose a hierarchy on a list of {@link GLCall}'s based on the presence of
+ * {@link Function#glPushGroupMarkerEXT} and {@link Function#glPopGroupMarkerEXT} calls.
+ * Such a hierarchy is possible only if calls from a single context are considered.
+ * @param trace trace to look at
+ * @param start starting call index
+ * @param end ending call index
+ * @param contextToGroup context from which calls should be grouped. If no such context
+ * is present, then all calls in the given range will be returned back as a flat
+ * list.
+ * @return a tree structured list of {@link GLCallNode} objects
+ */
+ public static List<GLCallNode> constructCallHierarchy(GLTrace trace, int start, int end,
+ int contextToGroup) {
+ if (trace == null) {
+ return Collections.emptyList();
+ }
+
+ if (contextToGroup < 0 || contextToGroup > trace.getContexts().size()) {
+ return flatHierarchy(trace, start, end);
+ }
+
+ List<GLCall> calls = trace.getGLCalls();
+
+ Stack<GLTreeNode> hierarchyStack = new Stack<GLTreeNode>();
+ List<GLCallNode> items = new ArrayList<GLCallNode>();
+
+ for (int i = start; i < end; i++) {
+ GLCall c = calls.get(i);
+ if (c.getContextId() != contextToGroup) {
+ // skip this call if it is not part of the context we need to display
+ continue;
+ }
+
+ if (c.getFunction() == Function.glPushGroupMarkerEXT) {
+ GLTreeNode group = new GLTreeNode(c);
+ if (hierarchyStack.size() > 0) {
+ hierarchyStack.peek().addChild(group);
+ } else {
+ items.add(group);
+ }
+ hierarchyStack.push(group);
+ } else if (c.getFunction() == Function.glPopGroupMarkerEXT) {
+ if (hierarchyStack.size() > 0) {
+ hierarchyStack.pop();
+ } else {
+ // FIXME: If we are attempting to pop from an empty stack,
+ // that implies that a push marker was seen in a prior frame
+ // (in a call before @start). In such a case, we simply continue
+ // adding further calls to the root of the hierarchy rather than
+ // searching backwards in the call list for the corresponding
+ // push markers.
+ items.add(new GLLeafNode(c));
+ }
+ } else {
+ GLLeafNode leaf = new GLLeafNode(c);
+ if (hierarchyStack.size() > 0) {
+ hierarchyStack.peek().addChild(leaf);
+ } else {
+ items.add(leaf);
+ }
+ }
+ }
+
+ return items;
+ }
+
+ private static List<GLCallNode> flatHierarchy(GLTrace trace, int start, int end) {
+ List<GLCallNode> items = new ArrayList<GLCallNode>();
+
+ List<GLCall> calls = trace.getGLCalls();
+ for (int i = start; i < end; i++) {
+ items.add(new GLLeafNode(calls.get(i)));
+ }
+
+ return items;
+ }
+}
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
new file mode 100644
index 000000000..b809ddddf
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java
@@ -0,0 +1,984 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.gltrace.editors;
+
+import com.android.ddmuilib.AbstractBufferFindTarget;
+import com.android.ddmuilib.FindDialog;
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function;
+import com.android.ide.eclipse.gltrace.GlTracePlugin;
+import com.android.ide.eclipse.gltrace.SwtUtils;
+import com.android.ide.eclipse.gltrace.TraceFileParserTask;
+import com.android.ide.eclipse.gltrace.editors.DurationMinimap.ICallSelectionListener;
+import com.android.ide.eclipse.gltrace.editors.GLCallGroups.GLCallNode;
+import com.android.ide.eclipse.gltrace.model.GLCall;
+import com.android.ide.eclipse.gltrace.model.GLFrame;
+import com.android.ide.eclipse.gltrace.model.GLTrace;
+import com.android.ide.eclipse.gltrace.views.FrameSummaryViewPage;
+import com.android.ide.eclipse.gltrace.views.detail.DetailsPage;
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Scale;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Spinner;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.part.EditorPart;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Display OpenGL function trace in a tabular view. */
+public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvider {
+ public static final String ID = "com.android.ide.eclipse.gltrace.GLFunctionTrace"; //$NON-NLS-1$
+
+ private static final String DEFAULT_FILTER_MESSAGE = "Filter list of OpenGL calls. Accepts Java regexes.";
+ private static final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$
+
+ private static Image sExpandAllIcon;
+
+ private static String sLastExportedToFolder;
+
+ private String mFilePath;
+ private Scale mFrameSelectionScale;
+ private Spinner mFrameSelectionSpinner;
+
+ private GLTrace mTrace;
+
+ private TreeViewer mFrameTreeViewer;
+ private List<GLCallNode> mTreeViewerNodes;
+
+ private Text mFilterText;
+ private GLCallFilter mGLCallFilter;
+
+ private Color mGldrawTextColor;
+ private Color mGlCallErrorColor;
+
+ /**
+ * Job to refresh the tree view & frame summary view.
+ *
+ * When the currently displayed frame is changed, either via the {@link #mFrameSelectionScale}
+ * or via {@link #mFrameSelectionSpinner}, we need to update the displayed tree of calls for
+ * that frame, and the frame summary view. Both these operations need to happen on the UI
+ * thread, but are time consuming. This works out ok if the frame selection is not changing
+ * rapidly (i.e., when the spinner or scale is moved to the target frame in a single action).
+ * However, if the spinner is constantly pressed, then the user is scrolling through a sequence
+ * of frames, and rather than refreshing the details for each of the intermediate frames,
+ * we create a job to refresh the details and schedule the job after a short interval
+ * {@link #TREE_REFRESH_INTERVAL}. This allows us to stay responsive to the spinner/scale,
+ * and not do the costly refresh for each of the intermediate frames.
+ */
+ private Job mTreeRefresherJob;
+ private final Object mTreeRefresherLock = new Object();
+ private static final int TREE_REFRESH_INTERVAL_MS = 250;
+
+ private int mCurrentFrame;
+
+ // Currently displayed frame's start and end call indices.
+ private int mCallStartIndex;
+ private int mCallEndIndex;
+
+ private DurationMinimap mDurationMinimap;
+ private ScrollBar mVerticalScrollBar;
+
+ private Combo mContextSwitchCombo;
+ private boolean mShowContextSwitcher;
+ private int mCurrentlyDisplayedContext = -1;
+
+ private StateViewPage mStateViewPage;
+ private FrameSummaryViewPage mFrameSummaryViewPage;
+ private DetailsPage mDetailsPage;
+
+ private ToolItem mExpandAllToolItem;
+ private ToolItem mCollapseAllToolItem;
+ private ToolItem mSaveAsToolItem;
+
+ public GLFunctionTraceViewer() {
+ mGldrawTextColor = Display.getDefault().getSystemColor(SWT.COLOR_BLUE);
+ mGlCallErrorColor = Display.getDefault().getSystemColor(SWT.COLOR_RED);
+ }
+
+ @Override
+ public void doSave(IProgressMonitor monitor) {
+ }
+
+ @Override
+ public void doSaveAs() {
+ }
+
+ @Override
+ public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+ // we use a IURIEditorInput to allow opening files not within the workspace
+ if (!(input instanceof IURIEditorInput)) {
+ throw new PartInitException("GL Function Trace View: unsupported input type.");
+ }
+
+ setSite(site);
+ setInput(input);
+ mFilePath = ((IURIEditorInput) input).getURI().getPath();
+
+ // set the editor part name to be the name of the file.
+ File f = new File(mFilePath);
+ setPartName(f.getName());
+ }
+
+ @Override
+ public boolean isDirty() {
+ return false;
+ }
+
+ @Override
+ public boolean isSaveAsAllowed() {
+ return false;
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ Composite c = new Composite(parent, SWT.NONE);
+ c.setLayout(new GridLayout(1, false));
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ c.setLayoutData(gd);
+
+ setInput(parent.getShell(), mFilePath);
+
+ createFrameSelectionControls(c);
+ createOptionsBar(c);
+ createFrameTraceView(c);
+
+ getSite().setSelectionProvider(mFrameTreeViewer);
+
+ IActionBars actionBars = getEditorSite().getActionBars();
+ actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(),
+ new Action("Copy") {
+ @Override
+ public void run() {
+ copySelectionToClipboard();
+ }
+ });
+
+ actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(),
+ new Action("Select All") {
+ @Override
+ public void run() {
+ selectAll();
+ }
+ });
+
+ actionBars.setGlobalActionHandler(ActionFactory.FIND.getId(),
+ new Action("Find") {
+ @Override
+ public void run() {
+ showFindDialog();
+ }
+ });
+ }
+
+ public void setInput(Shell shell, String tracePath) {
+ ProgressMonitorDialog dlg = new ProgressMonitorDialog(shell);
+ TraceFileParserTask parser = new TraceFileParserTask(mFilePath);
+ try {
+ dlg.run(true, true, parser);
+ } catch (InvocationTargetException e) {
+ // exception while parsing, display error to user
+ MessageDialog.openError(shell,
+ "Error parsing OpenGL Trace File",
+ e.getCause().getMessage());
+ return;
+ } catch (InterruptedException e) {
+ // operation canceled by user, just return
+ return;
+ }
+
+ mTrace = parser.getTrace();
+ mShowContextSwitcher = (mTrace == null) ? false : mTrace.getContexts().size() > 1;
+ if (mStateViewPage != null) {
+ mStateViewPage.setInput(mTrace);
+ }
+ if (mFrameSummaryViewPage != null) {
+ mFrameSummaryViewPage.setInput(mTrace);
+ }
+ if (mDetailsPage != null) {
+ mDetailsPage.setInput(mTrace);
+ }
+ if (mDurationMinimap != null) {
+ mDurationMinimap.setInput(mTrace);
+ }
+
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ refreshUI();
+ }
+ });
+ }
+
+ private void refreshUI() {
+ if (mTrace == null || mTrace.getGLCalls().size() == 0) {
+ setFrameCount(0);
+ return;
+ }
+
+ setFrameCount(mTrace.getFrames().size());
+ selectFrame(1);
+ }
+
+ private void createFrameSelectionControls(Composite parent) {
+ Composite c = new Composite(parent, SWT.NONE);
+ c.setLayout(new GridLayout(3, false));
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ c.setLayoutData(gd);
+
+ Label l = new Label(c, SWT.NONE);
+ l.setText("Select Frame:");
+
+ mFrameSelectionScale = new Scale(c, SWT.HORIZONTAL);
+ mFrameSelectionScale.setMinimum(1);
+ mFrameSelectionScale.setMaximum(1);
+ mFrameSelectionScale.setSelection(0);
+ gd = new GridData(GridData.FILL_HORIZONTAL);
+ mFrameSelectionScale.setLayoutData(gd);
+
+ mFrameSelectionScale.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ int selectedFrame = mFrameSelectionScale.getSelection();
+ mFrameSelectionSpinner.setSelection(selectedFrame);
+ selectFrame(selectedFrame);
+ }
+ });
+
+ mFrameSelectionSpinner = new Spinner(c, SWT.BORDER);
+ gd = new GridData();
+ // width to hold atleast 6 digits
+ gd.widthHint = SwtUtils.getApproximateFontWidth(mFrameSelectionSpinner) * 6;
+ mFrameSelectionSpinner.setLayoutData(gd);
+
+ mFrameSelectionSpinner.setMinimum(1);
+ mFrameSelectionSpinner.setMaximum(1);
+ mFrameSelectionSpinner.setSelection(0);
+ mFrameSelectionSpinner.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ int selectedFrame = mFrameSelectionSpinner.getSelection();
+ mFrameSelectionScale.setSelection(selectedFrame);
+ selectFrame(selectedFrame);
+ }
+ });
+ }
+
+ private void setFrameCount(int nFrames) {
+ boolean en = nFrames > 0;
+ mFrameSelectionScale.setEnabled(en);
+ mFrameSelectionSpinner.setEnabled(en);
+
+ mFrameSelectionScale.setMaximum(nFrames);
+ mFrameSelectionSpinner.setMaximum(nFrames);
+ }
+
+ private void selectFrame(int selectedFrame) {
+ mFrameSelectionScale.setSelection(selectedFrame);
+ mFrameSelectionSpinner.setSelection(selectedFrame);
+
+ synchronized (mTreeRefresherLock) {
+ if (mTrace != null) {
+ GLFrame f = mTrace.getFrame(selectedFrame - 1);
+ mCallStartIndex = f.getStartIndex();
+ mCallEndIndex = f.getEndIndex();
+ } else {
+ mCallStartIndex = mCallEndIndex = 0;
+ }
+
+ mCurrentFrame = selectedFrame - 1;
+
+ scheduleNewRefreshJob();
+ }
+
+ // update minimap view
+ mDurationMinimap.setCallRangeForCurrentFrame(mCallStartIndex, mCallEndIndex);
+ }
+
+ /**
+ * Show only calls from the given context
+ * @param context context id whose calls should be displayed. Illegal values will result in
+ * calls from all contexts being displayed.
+ */
+ private void selectContext(int context) {
+ if (mCurrentlyDisplayedContext == context) {
+ return;
+ }
+
+ synchronized (mTreeRefresherLock) {
+ mCurrentlyDisplayedContext = context;
+ scheduleNewRefreshJob();
+ }
+ }
+
+ private void scheduleNewRefreshJob() {
+ if (mTreeRefresherJob != null) {
+ return;
+ }
+
+ mTreeRefresherJob = new Job("Refresh GL Trace View Tree") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ final int start, end, context;
+
+ synchronized (mTreeRefresherLock) {
+ start = mCallStartIndex;
+ end = mCallEndIndex;
+ context = mCurrentlyDisplayedContext;
+
+ mTreeRefresherJob = null;
+ }
+
+ // update tree view in the editor
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ refreshTree(start, end, context);
+
+ // update the frame summary view
+ if (mFrameSummaryViewPage != null) {
+ mFrameSummaryViewPage.setSelectedFrame(mCurrentFrame);
+ }
+ }
+ });
+ return Status.OK_STATUS;
+ }
+ };
+ mTreeRefresherJob.setPriority(Job.SHORT);
+ mTreeRefresherJob.schedule(TREE_REFRESH_INTERVAL_MS);
+ }
+
+ private void refreshTree(int startCallIndex, int endCallIndex, int contextToDisplay) {
+ mTreeViewerNodes = GLCallGroups.constructCallHierarchy(mTrace,
+ startCallIndex, endCallIndex,
+ contextToDisplay);
+ mFrameTreeViewer.setInput(mTreeViewerNodes);
+ mFrameTreeViewer.refresh();
+ mFrameTreeViewer.expandAll();
+ }
+
+ private void createOptionsBar(Composite parent) {
+ int numColumns = mShowContextSwitcher ? 4 : 3;
+
+ Composite c = new Composite(parent, SWT.NONE);
+ c.setLayout(new GridLayout(numColumns, false));
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ c.setLayoutData(gd);
+
+ Label l = new Label(c, SWT.NONE);
+ l.setText("Filter:");
+
+ mFilterText = new Text(c, SWT.BORDER | SWT.ICON_SEARCH | SWT.SEARCH | SWT.ICON_CANCEL);
+ mFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ mFilterText.setMessage(DEFAULT_FILTER_MESSAGE);
+ mFilterText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ updateAppliedFilters();
+ }
+ });
+
+ if (mShowContextSwitcher) {
+ mContextSwitchCombo = new Combo(c, SWT.BORDER | SWT.READ_ONLY);
+
+ // Setup the combo such that "All Contexts" is the first item,
+ // and then we have an item for each context.
+ mContextSwitchCombo.add("All Contexts");
+ mContextSwitchCombo.select(0);
+ mCurrentlyDisplayedContext = -1; // showing all contexts
+ for (int i = 0; i < mTrace.getContexts().size(); i++) {
+ mContextSwitchCombo.add("Context " + i);
+ }
+
+ mContextSwitchCombo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ selectContext(mContextSwitchCombo.getSelectionIndex() - 1);
+ }
+ });
+ } else {
+ mCurrentlyDisplayedContext = 0;
+ }
+
+ ToolBar toolBar = new ToolBar(c, SWT.FLAT | SWT.BORDER);
+
+ mExpandAllToolItem = new ToolItem(toolBar, SWT.PUSH);
+ mExpandAllToolItem.setToolTipText("Expand All");
+ if (sExpandAllIcon == null) {
+ ImageDescriptor id = GlTracePlugin.getImageDescriptor("/icons/expandall.png");
+ sExpandAllIcon = id.createImage();
+ }
+ if (sExpandAllIcon != null) {
+ mExpandAllToolItem.setImage(sExpandAllIcon);
+ }
+
+ mCollapseAllToolItem = new ToolItem(toolBar, SWT.PUSH);
+ mCollapseAllToolItem.setToolTipText("Collapse All");
+ mCollapseAllToolItem.setImage(
+ PlatformUI.getWorkbench().getSharedImages().getImage(
+ ISharedImages.IMG_ELCL_COLLAPSEALL));
+
+ mSaveAsToolItem = new ToolItem(toolBar, SWT.PUSH);
+ mSaveAsToolItem.setToolTipText("Export Trace");
+ mSaveAsToolItem.setImage(
+ PlatformUI.getWorkbench().getSharedImages().getImage(
+ ISharedImages.IMG_ETOOL_SAVEAS_EDIT));
+
+ SelectionListener toolbarSelectionListener = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (e.getSource() == mCollapseAllToolItem) {
+ setTreeItemsExpanded(false);
+ } else if (e.getSource() == mExpandAllToolItem) {
+ setTreeItemsExpanded(true);
+ } else if (e.getSource() == mSaveAsToolItem) {
+ exportTrace();
+ }
+ }
+ };
+ mExpandAllToolItem.addSelectionListener(toolbarSelectionListener);
+ mCollapseAllToolItem.addSelectionListener(toolbarSelectionListener);
+ mSaveAsToolItem.addSelectionListener(toolbarSelectionListener);
+ }
+
+ private void updateAppliedFilters() {
+ mGLCallFilter.setFilters(mFilterText.getText().trim());
+ mFrameTreeViewer.refresh();
+ }
+
+ private void createFrameTraceView(Composite parent) {
+ Composite c = new Composite(parent, SWT.NONE);
+ c.setLayout(new GridLayout(2, false));
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ c.setLayoutData(gd);
+
+ final Tree tree = new Tree(c, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
+ gd = new GridData(GridData.FILL_BOTH);
+ tree.setLayoutData(gd);
+ tree.setLinesVisible(true);
+ tree.setHeaderVisible(true);
+
+ mFrameTreeViewer = new TreeViewer(tree);
+ CellLabelProvider labelProvider = new GLFrameLabelProvider();
+
+ // column showing the GL context id
+ TreeViewerColumn tvc = new TreeViewerColumn(mFrameTreeViewer, SWT.NONE);
+ tvc.setLabelProvider(labelProvider);
+ TreeColumn column = tvc.getColumn();
+ column.setText("Function");
+ column.setWidth(500);
+
+ // column showing the GL function duration (wall clock time)
+ tvc = new TreeViewerColumn(mFrameTreeViewer, SWT.NONE);
+ tvc.setLabelProvider(labelProvider);
+ column = tvc.getColumn();
+ column.setText("Wall Time (ns)");
+ column.setWidth(150);
+ column.setAlignment(SWT.RIGHT);
+
+ // column showing the GL function duration (thread time)
+ tvc = new TreeViewerColumn(mFrameTreeViewer, SWT.NONE);
+ tvc.setLabelProvider(labelProvider);
+ column = tvc.getColumn();
+ column.setText("Thread Time (ns)");
+ column.setWidth(150);
+ column.setAlignment(SWT.RIGHT);
+
+ mFrameTreeViewer.setContentProvider(new GLFrameContentProvider());
+
+ mGLCallFilter = new GLCallFilter();
+ mFrameTreeViewer.addFilter(mGLCallFilter);
+
+ // when the control is resized, give all the additional space
+ // to the function name column.
+ tree.addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent e) {
+ int w = mFrameTreeViewer.getTree().getClientArea().width;
+ if (w > 200) {
+ mFrameTreeViewer.getTree().getColumn(2).setWidth(100);
+ mFrameTreeViewer.getTree().getColumn(1).setWidth(100);
+ mFrameTreeViewer.getTree().getColumn(0).setWidth(w - 200);
+ }
+ }
+ });
+
+ mDurationMinimap = new DurationMinimap(c, mTrace);
+ gd = new GridData(GridData.FILL_VERTICAL);
+ gd.widthHint = gd.minimumWidth = mDurationMinimap.getMinimumWidth();
+ mDurationMinimap.setLayoutData(gd);
+ mDurationMinimap.addCallSelectionListener(new ICallSelectionListener() {
+ @Override
+ public void callSelected(int selectedCallIndex) {
+ if (selectedCallIndex > 0 && selectedCallIndex < mTreeViewerNodes.size()) {
+ TreeItem item = tree.getItem(selectedCallIndex);
+ tree.select(item);
+ tree.setTopItem(item);
+ }
+ }
+ });
+
+ mVerticalScrollBar = tree.getVerticalBar();
+ mVerticalScrollBar.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ updateVisibleRange();
+ }
+ });
+ }
+
+ private void updateVisibleRange() {
+ int visibleCallTopIndex = mCallStartIndex;
+ int visibleCallBottomIndex = mCallEndIndex;
+
+ if (mVerticalScrollBar.isEnabled()) {
+ int selection = mVerticalScrollBar.getSelection();
+ int thumb = mVerticalScrollBar.getThumb();
+ int max = mVerticalScrollBar.getMaximum();
+
+ // from the scrollbar values, compute the visible fraction
+ double top = (double) selection / max;
+ double bottom = (double) (selection + thumb) / max;
+
+ // map the fraction to the call indices
+ int range = mCallEndIndex - mCallStartIndex;
+ visibleCallTopIndex = mCallStartIndex + (int) Math.floor(range * top);
+ visibleCallBottomIndex = mCallStartIndex + (int) Math.ceil(range * bottom);
+ }
+
+ mDurationMinimap.setVisibleCallRange(visibleCallTopIndex, visibleCallBottomIndex);
+ }
+
+ @Override
+ public void setFocus() {
+ mFrameTreeViewer.getTree().setFocus();
+ }
+
+ private static class GLFrameContentProvider implements ITreeContentProvider {
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return getChildren(inputElement);
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof List<?>) {
+ return ((List<?>) parentElement).toArray();
+ }
+
+ if (!(parentElement instanceof GLCallNode)) {
+ return null;
+ }
+
+ GLCallNode parent = (GLCallNode) parentElement;
+ if (parent.hasChildren()) {
+ return parent.getChildren().toArray();
+ } else {
+ return new Object[0];
+ }
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ if (!(element instanceof GLCallNode)) {
+ return null;
+ }
+
+ return ((GLCallNode) element).getParent();
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ if (!(element instanceof GLCallNode)) {
+ return false;
+ }
+
+ return ((GLCallNode) element).hasChildren();
+ }
+ }
+
+ private class GLFrameLabelProvider extends ColumnLabelProvider {
+ @Override
+ public void update(ViewerCell cell) {
+ Object element = cell.getElement();
+ if (!(element instanceof GLCallNode)) {
+ return;
+ }
+
+ GLCall c = ((GLCallNode) element).getCall();
+
+ if (c.getFunction() == Function.glDrawArrays
+ || c.getFunction() == Function.glDrawElements) {
+ cell.setForeground(mGldrawTextColor);
+ }
+
+ if (c.hasErrors()) {
+ cell.setForeground(mGlCallErrorColor);
+ }
+
+ cell.setText(getColumnText(c, cell.getColumnIndex()));
+ }
+
+ private String getColumnText(GLCall c, int columnIndex) {
+ switch (columnIndex) {
+ case 0:
+ if (c.getFunction() == Function.glPushGroupMarkerEXT) {
+ Object marker = c.getProperty(GLCall.PROPERTY_MARKERNAME);
+ if (marker instanceof String) {
+ return ((String) marker);
+ }
+ }
+ return c.toString();
+ case 1:
+ return formatDuration(c.getWallDuration());
+ case 2:
+ return formatDuration(c.getThreadDuration());
+ default:
+ return Integer.toString(c.getContextId());
+ }
+ }
+
+ private String formatDuration(int time) {
+ // Max duration is in the 10s of milliseconds, so xx,xxx,xxx ns
+ // So we require a format specifier that is 10 characters wide
+ return String.format("%,10d", time); //$NON-NLS-1$
+ }
+ }
+
+ private static class GLCallFilter extends ViewerFilter {
+ private final List<Pattern> mPatterns = new ArrayList<Pattern>();
+
+ public void setFilters(String filter) {
+ mPatterns.clear();
+
+ // split the user input into multiple regexes
+ // we assume that the regexes are OR'ed together i.e., all text that matches
+ // any one of the regexes will be displayed
+ for (String regex : filter.split(" ")) {
+ mPatterns.add(Pattern.compile(regex, Pattern.CASE_INSENSITIVE));
+ }
+ }
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (!(element instanceof GLCallNode)) {
+ return true;
+ }
+
+ String text = getTextUnderNode((GLCallNode) element);
+
+ if (mPatterns.size() == 0) {
+ // match if there are no regex filters
+ return true;
+ }
+
+ for (Pattern p : mPatterns) {
+ Matcher matcher = p.matcher(text);
+ if (matcher.find()) {
+ // match if atleast one of the regexes matches this text
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /** Obtain a string representation of all functions under a given tree node. */
+ private String getTextUnderNode(GLCallNode element) {
+ String func = element.getCall().getFunction().toString();
+ if (!element.hasChildren()) {
+ return func;
+ }
+
+ StringBuilder sb = new StringBuilder(100);
+ sb.append(func);
+
+ for (GLCallNode child : element.getChildren()) {
+ sb.append(getTextUnderNode(child));
+ }
+
+ return sb.toString();
+ }
+ }
+
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ if (mFrameTreeViewer != null) {
+ mFrameTreeViewer.addSelectionChangedListener(listener);
+ }
+ }
+
+ @Override
+ public ISelection getSelection() {
+ if (mFrameTreeViewer != null) {
+ return mFrameTreeViewer.getSelection();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ if (mFrameTreeViewer != null) {
+ mFrameTreeViewer.removeSelectionChangedListener(listener);
+ }
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ if (mFrameTreeViewer != null) {
+ mFrameTreeViewer.setSelection(selection);
+ }
+ }
+
+ public GLTrace getTrace() {
+ return mTrace;
+ }
+
+ public StateViewPage getStateViewPage() {
+ if (mStateViewPage == null) {
+ mStateViewPage = new StateViewPage(mTrace);
+ }
+
+ return mStateViewPage;
+ }
+
+ public FrameSummaryViewPage getFrameSummaryViewPage() {
+ if (mFrameSummaryViewPage == null) {
+ mFrameSummaryViewPage = new FrameSummaryViewPage(mTrace);
+ }
+
+ return mFrameSummaryViewPage;
+ }
+
+ public DetailsPage getDetailsPage() {
+ if (mDetailsPage == null) {
+ mDetailsPage = new DetailsPage(mTrace);
+ }
+
+ return mDetailsPage;
+ }
+
+ private void copySelectionToClipboard() {
+ if (mFrameTreeViewer == null || mFrameTreeViewer.getTree().isDisposed()) {
+ return;
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ for (TreeItem it: mFrameTreeViewer.getTree().getSelection()) {
+ Object data = it.getData();
+ if (data instanceof GLCallNode) {
+ sb.append(((GLCallNode) data).getCall());
+ sb.append(NEWLINE);
+ }
+ }
+
+ if (sb.length() > 0) {
+ Clipboard cb = new Clipboard(Display.getDefault());
+ cb.setContents(
+ new Object[] { sb.toString() },
+ new Transfer[] { TextTransfer.getInstance() });
+ cb.dispose();
+ }
+ }
+
+ private void selectAll() {
+ if (mFrameTreeViewer == null || mFrameTreeViewer.getTree().isDisposed()) {
+ return;
+ }
+
+ mFrameTreeViewer.getTree().selectAll();
+ }
+
+ private void exportTrace() {
+ if (mFrameTreeViewer == null || mFrameTreeViewer.getTree().isDisposed()) {
+ return;
+ }
+
+ if (mCallEndIndex == 0) {
+ return;
+ }
+
+ FileDialog fd = new FileDialog(mFrameTreeViewer.getTree().getShell(), SWT.SAVE);
+ fd.setFilterExtensions(new String[] { "*.txt" });
+ if (sLastExportedToFolder != null) {
+ fd.setFilterPath(sLastExportedToFolder);
+ }
+
+ String path = fd.open();
+ if (path == null) {
+ return;
+ }
+
+ File f = new File(path);
+ sLastExportedToFolder = f.getParent();
+ try {
+ exportFrameTo(f);
+ } catch (IOException e) {
+ ErrorDialog.openError(mFrameTreeViewer.getTree().getShell(),
+ "Export trace file.",
+ "Unexpected error exporting trace file.",
+ new Status(Status.ERROR, GlTracePlugin.PLUGIN_ID, e.toString()));
+ }
+ }
+
+ private void exportFrameTo(File f) throws IOException {
+ String glCalls = serializeGlCalls(mTrace.getGLCalls(), mCallStartIndex, mCallEndIndex);
+ Files.write(glCalls, f, Charsets.UTF_8);
+ }
+
+ private String serializeGlCalls(List<GLCall> glCalls, int start, int end) {
+ StringBuilder sb = new StringBuilder();
+ while (start < end) {
+ sb.append(glCalls.get(start).toString());
+ sb.append("\n"); //$NON-NLS-1$
+ start++;
+ }
+
+ return sb.toString();
+ }
+
+ private void setTreeItemsExpanded(boolean expand) {
+ if (mFrameTreeViewer == null || mFrameTreeViewer.getTree().isDisposed()) {
+ return;
+ }
+
+ if (expand) {
+ mFrameTreeViewer.expandAll();
+ } else {
+ mFrameTreeViewer.collapseAll();
+ }
+ }
+
+ private class TraceViewerFindTarget extends AbstractBufferFindTarget {
+ @Override
+ public int getItemCount() {
+ return mFrameTreeViewer.getTree().getItemCount();
+ }
+
+ @Override
+ public String getItem(int index) {
+ Object data = mFrameTreeViewer.getTree().getItem(index).getData();
+ if (data instanceof GLCallNode) {
+ return ((GLCallNode) data).getCall().toString();
+ }
+ return null;
+ }
+
+ @Override
+ public void selectAndReveal(int index) {
+ Tree t = mFrameTreeViewer.getTree();
+ t.deselectAll();
+ t.select(t.getItem(index));
+ t.showSelection();
+ }
+
+ @Override
+ public int getStartingIndex() {
+ return 0;
+ }
+ };
+
+ private FindDialog mFindDialog;
+ private TraceViewerFindTarget mFindTarget = new TraceViewerFindTarget();
+
+ private void showFindDialog() {
+ if (mFindDialog != null) {
+ // the dialog is already displayed
+ return;
+ }
+
+ mFindDialog = new FindDialog(Display.getDefault().getActiveShell(),
+ mFindTarget,
+ FindDialog.FIND_NEXT_ID);
+ mFindDialog.open(); // blocks until find dialog is closed
+ mFindDialog = null;
+ }
+
+ public String getInputPath() {
+ return mFilePath;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateContentProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateContentProvider.java
new file mode 100644
index 000000000..7bff168fc
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateContentProvider.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.gltrace.editors;
+
+import com.android.ide.eclipse.gltrace.state.GLCompositeProperty;
+import com.android.ide.eclipse.gltrace.state.GLListProperty;
+import com.android.ide.eclipse.gltrace.state.GLSparseArrayProperty;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+public class StateContentProvider implements ITreeContentProvider {
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return getChildren(inputElement);
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof GLListProperty) {
+ return ((GLListProperty) parentElement).getList().toArray();
+ }
+
+ if (parentElement instanceof GLCompositeProperty) {
+ return ((GLCompositeProperty) parentElement).getProperties().toArray();
+ }
+
+ if (parentElement instanceof GLSparseArrayProperty) {
+ return ((GLSparseArrayProperty) parentElement).getValues().toArray();
+ }
+
+ return null;
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ if (element instanceof IGLProperty) {
+ return ((IGLProperty) element).getParent();
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ if (element instanceof IGLProperty) {
+ return ((IGLProperty) element).isComposite();
+ }
+
+ return false;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateLabelProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateLabelProvider.java
new file mode 100644
index 000000000..e37ea77fd
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateLabelProvider.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.gltrace.editors;
+
+import com.android.ide.eclipse.gltrace.state.GLListProperty;
+import com.android.ide.eclipse.gltrace.state.GLSparseArrayProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+
+import java.util.Set;
+
+public class StateLabelProvider extends ColumnLabelProvider {
+ private Set<IGLProperty> mChangedProperties;
+
+ private Color mHighlightForegroundColor;
+ private Color mNormalForegroundColor;
+
+ public StateLabelProvider() {
+ mHighlightForegroundColor = Display.getDefault().getSystemColor(SWT.COLOR_BLUE);
+ mNormalForegroundColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ }
+
+ public String getColumnText(IGLProperty property, int columnIndex) {
+ switch (columnIndex) {
+ case 0:
+ return getName(property);
+ case 1:
+ return getValue(property);
+ default:
+ return "";
+ }
+ }
+
+ private String getValue(IGLProperty element) {
+ return element.getStringValue();
+ }
+
+ private String getName(IGLProperty element) {
+ IGLProperty parent = element.getParent();
+ if (parent instanceof GLListProperty) {
+ // For members of list, use the index in the list as the name as opposed to
+ // the property type
+ int index = ((GLListProperty) parent).indexOf(element);
+ if (element.getType() == GLStateType.GL_STATE_ES1) {
+ return String.format("Context %d (ES1)", index);
+ } else if (element.getType() == GLStateType.GL_STATE_ES2) {
+ return String.format("Context %d (ES2)", index);
+ } else {
+ return Integer.toString(index);
+ }
+ } else if (parent instanceof GLSparseArrayProperty) {
+ // For members of sparse array, use the key as the name as opposed to
+ // the property type
+ int index = ((GLSparseArrayProperty) parent).keyFor(element);
+ return Integer.toString(index);
+ }
+
+ return element.getType().getDescription();
+ }
+
+ @Override
+ public void update(ViewerCell cell) {
+ Object element = cell.getElement();
+ if (!(element instanceof IGLProperty)) {
+ return;
+ }
+
+ IGLProperty prop = (IGLProperty) element;
+
+ String text = getColumnText(prop, cell.getColumnIndex());
+ cell.setText(text);
+
+ if (mChangedProperties != null && mChangedProperties.contains(prop)) {
+ cell.setForeground(mHighlightForegroundColor);
+ } else {
+ cell.setForeground(mNormalForegroundColor);
+ }
+ }
+
+ public void setChangedProperties(Set<IGLProperty> changedProperties) {
+ mChangedProperties = changedProperties;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateViewPage.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateViewPage.java
new file mode 100644
index 000000000..faa9561cb
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/StateViewPage.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.gltrace.editors;
+
+import com.android.ide.eclipse.gltrace.GlTracePlugin;
+import com.android.ide.eclipse.gltrace.editors.GLCallGroups.GLCallNode;
+import com.android.ide.eclipse.gltrace.model.GLCall;
+import com.android.ide.eclipse.gltrace.model.GLTrace;
+import com.android.ide.eclipse.gltrace.state.GLState;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+import com.android.ide.eclipse.gltrace.state.StatePrettyPrinter;
+import com.android.ide.eclipse.gltrace.state.transforms.IStateTransform;
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ILock;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.IPageSite;
+import org.eclipse.ui.part.Page;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A tree view of the OpenGL state. It listens to the current GLCall that is selected
+ * in the Function Trace view, and updates its view to reflect the state as of the selected call.
+ */
+public class StateViewPage extends Page implements ISelectionListener, ISelectionProvider {
+ public static final String ID = "com.android.ide.eclipse.gltrace.views.GLState"; //$NON-NLS-1$
+ private static String sLastUsedPath;
+ private static final ILock sGlStateLock = Job.getJobManager().newLock();
+
+ private GLTrace mTrace;
+ private List<GLCall> mGLCalls;
+
+ /** OpenGL State as of call {@link #mCurrentStateIndex}. */
+ private IGLProperty mState;
+ private int mCurrentStateIndex;
+
+ private String[] TREE_PROPERTIES = { "Name", "Value" };
+ private TreeViewer mTreeViewer;
+ private StateLabelProvider mLabelProvider;
+
+ public StateViewPage(GLTrace trace) {
+ setInput(trace);
+ }
+
+ public void setInput(GLTrace trace) {
+ mTrace = trace;
+ if (trace != null) {
+ mGLCalls = trace.getGLCalls();
+ } else {
+ mGLCalls = null;
+ }
+
+ mState = GLState.createDefaultState();
+ mCurrentStateIndex = -1;
+
+ if (mTreeViewer != null) {
+ mTreeViewer.setInput(mState);
+ mTreeViewer.refresh();
+ }
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.H_SCROLL | SWT.V_SCROLL);
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(tree);
+
+ tree.setHeaderVisible(true);
+ tree.setLinesVisible(true);
+ tree.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ TreeColumn col1 = new TreeColumn(tree, SWT.LEFT);
+ col1.setText(TREE_PROPERTIES[0]);
+ col1.setWidth(200);
+
+ TreeColumn col2 = new TreeColumn(tree, SWT.LEFT);
+ col2.setText(TREE_PROPERTIES[1]);
+ col2.setWidth(200);
+
+ mTreeViewer = new TreeViewer(tree);
+ mTreeViewer.setContentProvider(new StateContentProvider());
+ mLabelProvider = new StateLabelProvider();
+ mTreeViewer.setLabelProvider(mLabelProvider);
+ mTreeViewer.setInput(mState);
+ mTreeViewer.refresh();
+
+ final IToolBarManager manager = getSite().getActionBars().getToolBarManager();
+ manager.add(new Action("Save to File",
+ PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(
+ ISharedImages.IMG_ETOOL_SAVEAS_EDIT)) {
+ @Override
+ public void run() {
+ saveCurrentState();
+ }
+ });
+ }
+
+ private void saveCurrentState() {
+ final Shell shell = mTreeViewer.getTree().getShell();
+ FileDialog fd = new FileDialog(shell, SWT.SAVE);
+ fd.setFilterExtensions(new String[] { "*.txt" });
+ if (sLastUsedPath != null) {
+ fd.setFilterPath(sLastUsedPath);
+ }
+
+ String path = fd.open();
+ if (path == null) {
+ return;
+ }
+
+ File f = new File(path);
+ sLastUsedPath = f.getParent();
+
+ // export state to f
+ StatePrettyPrinter pp = new StatePrettyPrinter();
+ synchronized (sGlStateLock) {
+ mState.prettyPrint(pp);
+ }
+
+ try {
+ Files.write(pp.toString(), f, Charsets.UTF_8);
+ } catch (IOException e) {
+ ErrorDialog.openError(shell,
+ "Export GL State",
+ "Unexpected error while writing GL state to file.",
+ new Status(Status.ERROR, GlTracePlugin.PLUGIN_ID, e.toString()));
+ }
+ }
+
+ @Override
+ public void init(IPageSite pageSite) {
+ super.init(pageSite);
+ pageSite.getPage().addSelectionListener(this);
+ }
+
+ @Override
+ public void dispose() {
+ getSite().getPage().removeSelectionListener(this);
+ super.dispose();
+ }
+
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if (!(part instanceof GLFunctionTraceViewer)) {
+ return;
+ }
+
+ if (((GLFunctionTraceViewer) part).getTrace() != mTrace) {
+ return;
+ }
+
+ if (!(selection instanceof TreeSelection)) {
+ return;
+ }
+
+ GLCall selectedCall = null;
+
+ Object data = ((TreeSelection) selection).getFirstElement();
+ if (data instanceof GLCallNode) {
+ selectedCall = ((GLCallNode) data).getCall();
+ }
+
+ if (selectedCall == null) {
+ return;
+ }
+
+ final int selectedCallIndex = selectedCall.getIndex();
+
+ // Creation of texture images takes a few seconds on the first run. So run
+ // the update task as an Eclipse job.
+ Job job = new Job("Updating GL State") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ Set<IGLProperty> changedProperties = null;
+
+ try {
+ sGlStateLock.acquire();
+ changedProperties = updateState(mCurrentStateIndex,
+ selectedCallIndex);
+ mCurrentStateIndex = selectedCallIndex;
+ } catch (Exception e) {
+ GlTracePlugin.getDefault().logMessage(
+ "Unexpected error while updating GL State.");
+ GlTracePlugin.getDefault().logMessage(e.getMessage());
+ return new Status(Status.ERROR,
+ GlTracePlugin.PLUGIN_ID,
+ "Unexpected error while updating GL State.",
+ e);
+ } finally {
+ sGlStateLock.release();
+ }
+
+ mLabelProvider.setChangedProperties(changedProperties);
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!mTreeViewer.getTree().isDisposed()) {
+ mTreeViewer.refresh();
+ }
+ }
+ });
+
+ return Status.OK_STATUS;
+ }
+ };
+ job.setPriority(Job.SHORT);
+ job.schedule();
+ }
+
+ @Override
+ public Control getControl() {
+ if (mTreeViewer == null) {
+ return null;
+ }
+
+ return mTreeViewer.getControl();
+ }
+
+ @Override
+ public void setFocus() {
+ }
+
+ /**
+ * Update GL state from GL call at fromIndex to the call at toIndex.
+ * If fromIndex < toIndex, the GL state will be updated by applying all the transformations
+ * corresponding to calls from (fromIndex + 1) to toIndex (inclusive).
+ * If fromIndex > toIndex, the GL state will be updated by reverting all the calls from
+ * fromIndex (inclusive) to (toIndex + 1).
+ * @return GL state properties that changed as a result of this update.
+ */
+ private Set<IGLProperty> updateState(int fromIndex, int toIndex) {
+ assert fromIndex >= -1 && fromIndex < mGLCalls.size();
+ assert toIndex >= 0 && toIndex < mGLCalls.size();
+
+ if (fromIndex < toIndex) {
+ return applyTransformations(fromIndex, toIndex);
+ } else if (fromIndex > toIndex) {
+ return revertTransformations(fromIndex, toIndex);
+ } else {
+ return Collections.emptySet();
+ }
+ }
+
+ private Set<IGLProperty> applyTransformations(int fromIndex, int toIndex) {
+ int setSizeHint = 3 * (toIndex - fromIndex) + 10;
+ Set<IGLProperty> changedProperties = new HashSet<IGLProperty>(setSizeHint);
+
+ for (int i = fromIndex + 1; i <= toIndex; i++) {
+ GLCall call = mGLCalls.get(i);
+ for (IStateTransform f : call.getStateTransformations()) {
+ try {
+ f.apply(mState);
+ IGLProperty changedProperty = f.getChangedProperty(mState);
+ if (changedProperty != null) {
+ changedProperties.addAll(getHierarchy(changedProperty));
+ }
+ } catch (Exception e) {
+ GlTracePlugin.getDefault().logMessage("Error applying transformations for "
+ + call);
+ GlTracePlugin.getDefault().logMessage(e.toString());
+ }
+ }
+ }
+
+ return changedProperties;
+ }
+
+ private Set<IGLProperty> revertTransformations(int fromIndex, int toIndex) {
+ int setSizeHint = 3 * (fromIndex - toIndex) + 10;
+ Set<IGLProperty> changedProperties = new HashSet<IGLProperty>(setSizeHint);
+
+ for (int i = fromIndex; i > toIndex; i--) {
+ List<IStateTransform> transforms = mGLCalls.get(i).getStateTransformations();
+ // When reverting transformations, iterate from the last to first so that the reversals
+ // are performed in the correct sequence.
+ for (int j = transforms.size() - 1; j >= 0; j--) {
+ IStateTransform f = transforms.get(j);
+ f.revert(mState);
+
+ IGLProperty changedProperty = f.getChangedProperty(mState);
+ if (changedProperty != null) {
+ changedProperties.addAll(getHierarchy(changedProperty));
+ }
+ }
+ }
+
+ return changedProperties;
+ }
+
+ /**
+ * Obtain the list of properties starting from the provided property up to
+ * the root of GL state.
+ */
+ private List<IGLProperty> getHierarchy(IGLProperty changedProperty) {
+ List<IGLProperty> changedProperties = new ArrayList<IGLProperty>(5);
+ changedProperties.add(changedProperty);
+
+ // add the entire parent chain until we reach the root
+ IGLProperty prop = changedProperty;
+ while ((prop = prop.getParent()) != null) {
+ changedProperties.add(prop);
+ }
+
+ return changedProperties;
+ }
+
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ mTreeViewer.addSelectionChangedListener(listener);
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return mTreeViewer.getSelection();
+ }
+
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ mTreeViewer.removeSelectionChangedListener(listener);
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ mTreeViewer.setSelection(selection);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLAPISpec.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLAPISpec.java
new file mode 100644
index 000000000..57b587cb3
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLAPISpec.java
@@ -0,0 +1,134 @@
+/*
+ * 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.format;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Model a single GL API function call's specification.
+ */
+public class GLAPISpec {
+ private static final String GL_SPECS_FILE = "/entries.in"; //$NON-NLS-1$
+ private static final String GLES2_ENTRIES_HEADER_V1 =
+ "# com.android.ide.eclipse.gltrace.glentries, v1"; //$NON-NLS-1$
+ private static Map<String, GLAPISpec> sApiSpecs;
+
+ private final String mGLFunction;
+ private final GLDataTypeSpec mReturnType;
+ private final List<GLDataTypeSpec> mArgs;
+
+ private GLAPISpec(String glFunction, GLDataTypeSpec returnType, List<GLDataTypeSpec> args) {
+ mGLFunction = glFunction;
+ mReturnType = returnType;
+ mArgs = args;
+ }
+
+ public String getFunction() {
+ return mGLFunction;
+ }
+
+ public GLDataTypeSpec getReturnValue() {
+ return mReturnType;
+ }
+
+ public List<GLDataTypeSpec> getArgs() {
+ return mArgs;
+ }
+
+ public static Map<String, GLAPISpec> getSpecs() {
+ if (sApiSpecs == null) {
+ sApiSpecs = parseApiSpecs(GLAPISpec.class.getResourceAsStream(GL_SPECS_FILE));
+ }
+
+ return sApiSpecs;
+ }
+
+ private static Map<String, GLAPISpec> parseApiSpecs(InputStream specFile) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(specFile));
+ Map<String, GLAPISpec> specs = new HashMap<String, GLAPISpec>(400);
+
+ try{
+ String header = reader.readLine().trim();
+ assert header.equals(GLES2_ENTRIES_HEADER_V1);
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ // strip away the comments
+ int commentPos = line.indexOf('#');
+ if (commentPos != -1) {
+ line = line.substring(0, commentPos);
+ }
+ line = line.trim();
+
+ // parse non empty lines
+ if (line.length() > 0) {
+ GLAPISpec spec = parseLine(line);
+ specs.put(spec.getFunction(), spec);
+ }
+ }
+
+ specFile.close();
+ } catch (IOException e) {
+ // this is unlikely to happen as the file is present within this .jar file.
+ // Even if it does happen, we just return whatever we've read till now. The net
+ // impact will be that the function calls will not be parsed fully and will just
+ // display the function name.
+ }
+
+ return specs;
+ }
+
+ /**
+ * Parse a GL API Specification entry from "/entries.in". Each line is of the format:
+ * {@code returnType, funcName, arg*}. This method is package private for testing.
+ */
+ static GLAPISpec parseLine(String line) {
+ List<String> words = Arrays.asList(line.split(","));
+
+ String retType = words.get(0).trim();
+ String func = words.get(1).trim();
+ List<String> argDefinitions = words.subList(2, words.size());
+
+ List<GLDataTypeSpec> glArgs = new ArrayList<GLDataTypeSpec>(argDefinitions.size()/2);
+ for (String argDefn: argDefinitions) {
+ // an argDefn is something like: "const GLvoid* data"
+ argDefn = argDefn.trim();
+ int lastSeparator = argDefn.lastIndexOf(' ');
+ if (lastSeparator == -1) {
+ // no space => a void type with no argument name
+ glArgs.add(new GLDataTypeSpec(argDefn, null));
+ } else {
+ // everything upto the last space is the type
+ String type = argDefn.substring(0, lastSeparator);
+
+ // and the last word is the variable name
+ String name = argDefn.substring(lastSeparator + 1);
+ glArgs.add(new GLDataTypeSpec(type, name));
+ }
+ }
+
+ return new GLAPISpec(func, new GLDataTypeSpec(retType, null), glArgs);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLDataTypeSpec.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLDataTypeSpec.java
new file mode 100644
index 000000000..de9c9b686
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLDataTypeSpec.java
@@ -0,0 +1,75 @@
+/*
+ * 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.format;
+
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type;
+
+public class GLDataTypeSpec {
+ private final String mCType;
+ private final Type mType;
+ private final String mName;
+ private final boolean mIsPointer;
+
+ public GLDataTypeSpec(String type, String name) {
+ mCType = type;
+ mName = name;
+
+ mType = getDataType(type);
+ mIsPointer = type.contains("*"); //$NON-NLS-1$
+ }
+
+ private Type getDataType(String type) {
+ type = type.toLowerCase();
+
+ // We use type.contains() rather than type.equals since we are matching against
+ // the type name along with qualifiers. e.g. "void", "GLvoid" and "void*" should
+ // all be assigned the same type.
+ if (type.contains("boolean")) { //$NON-NLS-1$
+ return Type.BOOL;
+ } else if (type.contains("enum")) { //$NON-NLS-1$
+ return Type.ENUM;
+ } else if (type.contains("float") || type.contains("clampf")) { //$NON-NLS-1$ //$NON-NLS-2$
+ return Type.FLOAT;
+ } else if (type.contains("void")) { //$NON-NLS-1$
+ return Type.VOID;
+ } else if (type.contains("char")) { //$NON-NLS-1$
+ return Type.CHAR;
+ } else {
+ // Matches all of the following types:
+ // glclampx, gluint, glint, glshort, glsizei, glfixed,
+ // glsizeiptr, glintptr, glbitfield, glfixed, glubyte.
+ // We might do custom formatting for these types in the future.
+ return Type.INT;
+ }
+ }
+
+ public Type getDataType() {
+ return mType;
+ }
+
+ public String getCType() {
+ return mCType;
+ }
+
+ public String getArgName() {
+ return mName;
+ }
+
+ public boolean isPointer() {
+ return mIsPointer;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLMessageFormatter.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLMessageFormatter.java
new file mode 100644
index 000000000..6c34005ac
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/format/GLMessageFormatter.java
@@ -0,0 +1,166 @@
+/*
+ * 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.format;
+
+import com.android.ide.eclipse.gltrace.GLEnum;
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage;
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType;
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.DataType.Type;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * GLMessageFormatter is used to format and create a string representation for a {@link GLMessage}.
+ * It is provided with a specification for all GL Functions. Using this information, each
+ * GLMessage is parsed and formatted appropriately for display.
+ */
+public class GLMessageFormatter {
+ private static final String GL_NO_ERROR = "GL_NO_ERROR";
+ private Map<String, GLAPISpec> mAPISpecs;
+ private enum DataTypeContext { CONTEXT_ARGUMENT, CONTEXT_RETURNVALUE };
+
+ public GLMessageFormatter(Map<String, GLAPISpec> specs) {
+ mAPISpecs = specs;
+ }
+
+ public String formatGLMessage(GLMessage glMessage) {
+ GLAPISpec apiSpec = mAPISpecs.get(glMessage.getFunction().toString());
+ if (apiSpec == null) {
+ return glMessage.getFunction().toString();
+ }
+
+ return formatCall(apiSpec, glMessage) + formatReturnValue(apiSpec, glMessage);
+ }
+
+ private String formatReturnValue(GLAPISpec apiSpec, GLMessage glMessage) {
+ if (apiSpec.getReturnValue().getDataType() == Type.VOID) {
+ return "";
+ }
+
+ GLDataTypeSpec returnSpec = apiSpec.getReturnValue();
+ return String.format(" = (%s) %s", returnSpec.getCType(), //$NON-NLS-1$
+ formatDataValue(glMessage.getReturnValue(),
+ returnSpec,
+ DataTypeContext.CONTEXT_RETURNVALUE));
+ }
+
+ private String formatCall(GLAPISpec apiSpec, GLMessage glMessage) {
+ return String.format("%s(%s)", apiSpec.getFunction(), //$NON-NLS-1$
+ formatArgs(glMessage, apiSpec.getArgs()));
+ }
+
+ private String formatArgs(GLMessage glMessage, List<GLDataTypeSpec> argSpecs) {
+ int sizeEstimate = 10 + argSpecs.size() * 5;
+ StringBuilder sb = new StringBuilder(sizeEstimate);
+
+ for (int i = 0; i < argSpecs.size(); i++) {
+ GLDataTypeSpec argSpec = argSpecs.get(i);
+
+ if (argSpec.getDataType() == Type.VOID && !argSpec.isPointer()) {
+ sb.append("void"); //$NON-NLS-1$
+ } else {
+ sb.append(argSpec.getArgName());
+ sb.append(" = "); //$NON-NLS-1$
+ sb.append(formatDataValue(glMessage.getArgs(i),
+ argSpec,
+ DataTypeContext.CONTEXT_ARGUMENT));
+ }
+
+ if (i < argSpecs.size() - 1) {
+ sb.append(", "); //$NON-NLS-1$
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private String formatDataValue(DataType var, GLDataTypeSpec typeSpec, DataTypeContext context) {
+ if (typeSpec.isPointer()) {
+ return formatPointer(var, typeSpec.getDataType());
+ }
+
+ switch (typeSpec.getDataType()) {
+ case VOID:
+ return "";
+ case BOOL:
+ return Boolean.toString(var.getBoolValue(0));
+ case FLOAT:
+ return String.format("%f", var.getFloatValue(0)); //$NON-NLS-1$
+ case INT:
+ return Integer.toString(var.getIntValue(0));
+ case ENUM:
+ if (var.getIntValue(0) == 0 && context == DataTypeContext.CONTEXT_RETURNVALUE) {
+ return GL_NO_ERROR;
+ } else {
+ return GLEnum.valueOf(var.getIntValue(0)).toString();
+ }
+ default:
+ return "(unknown type)"; //$NON-NLS-1$
+ }
+ }
+
+ private String formatPointer(DataType var, Type typeSpec) {
+ if (var.getType() != typeSpec && !isEnumTypeWithIntData(var, typeSpec)) {
+ // the type of the data in the message does not match expected specification.
+ // in such a case, just print the data as a pointer and don't try to interpret it.
+ if (var.getIntValueCount() > 0) {
+ return String.format("0x%x", var.getIntValue(0)); //$NON-NLS-1$
+ } else {
+ return "0x??"; //$NON-NLS-1$
+ }
+ }
+
+ // Display as array if possible
+ switch (typeSpec) {
+ case BOOL:
+ return var.getBoolValueList().toString();
+ case FLOAT:
+ return var.getFloatValueList().toString();
+ case INT:
+ return var.getIntValueList().toString();
+ case CHAR:
+ return var.getCharValueList().get(0).toStringUtf8();
+ case ENUM:
+ List<Integer> vals = var.getIntValueList();
+ StringBuilder sb = new StringBuilder(vals.size() * 5);
+ sb.append('[');
+ for (Integer v: vals) {
+ sb.append(GLEnum.valueOf(v.intValue()));
+ }
+ sb.append(']');
+ return sb.toString();
+ case VOID:
+ if (var.getRawBytesList().size() > 0) {
+ return String.format("[ %d bytes ]", var.getRawBytesList().get(0).size()); //$NON-NLS-1$
+ }
+ return "[]"; //$NON-NLS-1$
+ }
+
+ // We have a pointer, but we don't have the data pointed to.
+ // Just format and return the pointer (points to device memory)
+ if (var.getIntValue(0) == 0) {
+ return "NULL"; //$NON-NLS-1$
+ } else {
+ return String.format("0x%x", var.getIntValue(0)); //$NON-NLS-1$
+ }
+ }
+
+ private boolean isEnumTypeWithIntData(DataType var, Type typeSpec) {
+ return var.getType() == Type.INT && typeSpec == Type.ENUM;
+ }
+}
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
new file mode 100644
index 000000000..0f6a11646
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLCall.java
@@ -0,0 +1,183 @@
+/*
+ * 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.model;
+
+import com.android.ide.eclipse.gltrace.GLProtoBuf;
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function;
+import com.android.ide.eclipse.gltrace.state.transforms.IStateTransform;
+import com.android.utils.SparseArray;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A GLCall is the in memory representation of a single {@link GLProtoBuf.GLMessage}.
+ *
+ * Some protocol buffer messages have a large amount of image data packed in them. Rather
+ * than storing all of that in memory, the GLCall stores a thumbnail image, and an offset
+ * into the trace file corresponding to original protocol buffer message. If full image data
+ * is required, the protocol buffer message can be recreated by reading the trace at the
+ * specified offset.
+ */
+public class GLCall {
+ /** Marker name provided by a {@link Function#glPushGroupMarkerEXT} call. */
+ public static final int PROPERTY_MARKERNAME = 0;
+
+ /** Size argument in a {@link Function#glVertexAttribPointerData} call. */
+ public static final int PROPERTY_VERTEX_ATTRIB_POINTER_SIZE = 1;
+
+ /** Type argument in a {@link Function#glVertexAttribPointerData} call. */
+ public static final int PROPERTY_VERTEX_ATTRIB_POINTER_TYPE = 2;
+
+ /** Data argument in a {@link Function#glVertexAttribPointerData} call. */
+ public static final int PROPERTY_VERTEX_ATTRIB_POINTER_DATA = 3;
+
+ /** Index of this call in the trace. */
+ private int mIndex;
+
+ /** Time on device when this call was invoked. */
+ private final long mStartTime;
+
+ /** Offset of the protobuf message corresponding to this call in the trace file. */
+ private final long mTraceFileOffset;
+
+ /** Flag indicating whether the original protobuf message included FB data. */
+ private final boolean mHasFb;
+
+ /** Full string representation of this call. */
+ private final String mDisplayString;
+
+ /** The actual GL Function called. */
+ private final Function mFunction;
+
+ /** GL Context identifier corresponding to the context of this call. */
+ private final int mContextId;
+
+ /** Duration of this call (MONOTONIC/wall clock time). */
+ private final int mWallDuration;
+
+ /** Duration of this call (THREAD time). */
+ private final int mThreadDuration;
+
+ /** List of state transformations performed by this call. */
+ private List<IStateTransform> mStateTransforms = Collections.emptyList();
+
+ /** Error conditions while creating state transforms for this call. */
+ private String mStateTransformationCreationErrorMessage;
+
+ /** List of properties associated to this call. */
+ private SparseArray<Object> mProperties;
+
+ public GLCall(int index, long startTime, long traceFileOffset, String displayString,
+ Function function, boolean hasFb, int contextId,
+ int wallTime, int threadTime) {
+ mIndex = index;
+ mStartTime = startTime;
+ mTraceFileOffset = traceFileOffset;
+ mDisplayString = displayString;
+ mFunction = function;
+ mHasFb = hasFb;
+ mContextId = contextId;
+ mWallDuration = wallTime;
+ mThreadDuration = threadTime;
+ }
+
+ public int getIndex() {
+ return mIndex;
+ }
+
+ public void setIndex(int i) {
+ mIndex = i;
+ }
+
+ public long getOffsetInTraceFile() {
+ return mTraceFileOffset;
+ }
+
+ public Function getFunction() {
+ return mFunction;
+ }
+
+ public int getContextId() {
+ return mContextId;
+ }
+
+ public boolean hasFb() {
+ return mHasFb;
+ }
+
+ public long getStartTime() {
+ return mStartTime;
+ }
+
+ public int getWallDuration() {
+ return mWallDuration;
+ }
+
+ public int getThreadDuration() {
+ return mThreadDuration;
+ }
+
+ public void setStateTransformations(List<IStateTransform> transforms) {
+ mStateTransforms = transforms;
+ }
+
+ public void setStateTransformationCreationError(String errorMessage) {
+ mStateTransformationCreationErrorMessage = errorMessage;
+ }
+
+ public boolean hasErrors() {
+ return mStateTransformationCreationErrorMessage != null;
+ }
+
+ public String getError() {
+ return mStateTransformationCreationErrorMessage;
+ }
+
+ public List<IStateTransform> getStateTransformations() {
+ return mStateTransforms;
+ }
+
+ @Override
+ public String toString() {
+ return mDisplayString;
+ }
+
+ /**
+ * Associate a certain value to the property name. Property names are defined
+ * as constants in {@link GLCall}.
+ */
+ public void addProperty(int propertyName, Object value) {
+ if (mProperties == null) {
+ mProperties = new SparseArray<Object>(1);
+ }
+
+ mProperties.put(propertyName, value);
+ }
+
+ /**
+ * Obtain the value for the given property. Returns null if no such property
+ * is associated with this {@link GLCall}.
+ */
+ public Object getProperty(int propertyName) {
+ if (mProperties == null) {
+ return null;
+ }
+
+ return mProperties.get(propertyName);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLFrame.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLFrame.java
new file mode 100644
index 000000000..5ff07a4f9
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLFrame.java
@@ -0,0 +1,51 @@
+/*
+ * 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.model;
+
+/**
+ * A GLFrame is used to keep track of the start and end {@link GLCall} indices
+ * for each OpenGL frame.
+ */
+public class GLFrame {
+ private final int mIndex;
+ private final int mStartCallIndex;
+ private final int mEndCallIndex;
+
+ /**
+ * Construct a {@link GLFrame} given the range of {@link GLCall}s spanning this frame.
+ * @param frameIndex index of this frame in the trace.
+ * @param startCallIndex index of the first call in this frame (inclusive).
+ * @param endCallIndex index of the last call in this frame (exclusive).
+ */
+ public GLFrame(int frameIndex, int startCallIndex, int endCallIndex) {
+ mIndex = frameIndex;
+ mStartCallIndex = startCallIndex;
+ mEndCallIndex = endCallIndex;
+ }
+
+ public int getIndex() {
+ return mIndex;
+ }
+
+ public int getStartIndex() {
+ return mStartCallIndex;
+ }
+
+ public int getEndIndex() {
+ return mEndCallIndex;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLTrace.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLTrace.java
new file mode 100644
index 000000000..766764466
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/model/GLTrace.java
@@ -0,0 +1,120 @@
+/*
+ * 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.model;
+
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage;
+import com.android.ide.eclipse.gltrace.ProtoBufUtils;
+import com.android.ide.eclipse.gltrace.TraceFileInfo;
+import com.android.ide.eclipse.gltrace.TraceFileReader;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Collections;
+import java.util.List;
+
+/** GLTrace is the in memory model of a OpenGL trace file. */
+public class GLTrace {
+ private static final TraceFileReader sTraceFileReader = new TraceFileReader();
+
+ /** Information regarding the trace file. */
+ private final TraceFileInfo mTraceFileInfo;
+
+ /** List of frames in the trace. */
+ private final List<GLFrame> mGLFrames;
+
+ /** List of GL Calls comprising the trace. */
+ private final List<GLCall> mGLCalls;
+
+ /** List of context ids used by the application. */
+ private List<Integer> mContextIds;
+
+ public GLTrace(TraceFileInfo traceFileInfo, List<GLFrame> glFrames, List<GLCall> glCalls,
+ List<Integer> contextIds) {
+ mTraceFileInfo = traceFileInfo;
+ mGLFrames = glFrames;
+ mGLCalls = glCalls;
+ mContextIds = contextIds;
+ }
+
+ public List<GLFrame> getFrames() {
+ return mGLFrames;
+ }
+
+ public GLFrame getFrame(int i) {
+ return mGLFrames.get(i);
+ }
+
+ public List<GLCall> getGLCalls() {
+ return mGLCalls;
+ }
+
+ public List<GLCall> getGLCallsForFrame(int frameIndex) {
+ if (frameIndex >= mGLFrames.size()) {
+ return Collections.emptyList();
+ }
+
+ GLFrame frame = mGLFrames.get(frameIndex);
+ return mGLCalls.subList(frame.getStartIndex(), frame.getEndIndex());
+ }
+
+ public Image getImage(GLCall c) {
+ if (!c.hasFb()) {
+ return null;
+ }
+
+ if (isTraceFileModified()) {
+ return null;
+ }
+
+ RandomAccessFile file;
+ try {
+ file = new RandomAccessFile(mTraceFileInfo.getPath(), "r"); //$NON-NLS-1$
+ } catch (FileNotFoundException e1) {
+ return null;
+ }
+
+ GLMessage m = null;
+ try {
+ m = sTraceFileReader.getMessageAtOffset(file, c.getOffsetInTraceFile());
+ } catch (Exception e) {
+ return null;
+ } finally {
+ try {
+ file.close();
+ } catch (IOException e) {
+ // ignore exception while closing file
+ }
+ }
+
+ return ProtoBufUtils.getImage(Display.getCurrent(), m);
+ }
+
+ private boolean isTraceFileModified() {
+ File f = new File(mTraceFileInfo.getPath());
+ return f.length() != mTraceFileInfo.getSize()
+ || f.lastModified() != mTraceFileInfo.getLastModificationTime();
+ }
+
+ public List<Integer> getContexts() {
+ return mContextIds;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/DisplayRadix.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/DisplayRadix.java
new file mode 100644
index 000000000..935f4d79c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/DisplayRadix.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 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.state;
+
+public enum DisplayRadix {
+ DECIMAL, HEX
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLAbstractAtomicProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLAbstractAtomicProperty.java
new file mode 100644
index 000000000..cb96312b8
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLAbstractAtomicProperty.java
@@ -0,0 +1,65 @@
+/*
+ * 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.state;
+
+
+/**
+ * Abstract implementation of {@link IGLProperty}. This provides the basics that can be
+ * used by leaf level properties.
+ */
+public abstract class GLAbstractAtomicProperty implements IGLProperty {
+ private final GLStateType mType;
+ private IGLProperty mParent;
+
+ public GLAbstractAtomicProperty(GLStateType type) {
+ mType = type;
+ }
+
+ @Override
+ public GLStateType getType() {
+ return mType;
+ }
+
+ @Override
+ public IGLProperty getParent() {
+ return mParent;
+ }
+
+ @Override
+ public void setParent(IGLProperty parent) {
+ mParent = parent;
+ }
+
+ @Override
+ public boolean isComposite() {
+ return false;
+ }
+
+ @Override
+ public IGLProperty clone() {
+ try {
+ return (IGLProperty) super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void prettyPrint(StatePrettyPrinter pp) {
+ pp.prettyPrint(mType, getStringValue());
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLBooleanProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLBooleanProperty.java
new file mode 100644
index 000000000..8332b0a65
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLBooleanProperty.java
@@ -0,0 +1,64 @@
+/*
+ * 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.state;
+
+
+/** Properties that hold boolean values. */
+public final class GLBooleanProperty extends GLAbstractAtomicProperty {
+ private final Boolean mDefaultValue;
+ private Boolean mCurrentValue;
+
+ public GLBooleanProperty(GLStateType name, Boolean defaultValue) {
+ super(name);
+
+ mDefaultValue = mCurrentValue = defaultValue;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return mDefaultValue != null & mDefaultValue.equals(mCurrentValue);
+ }
+
+ public void setValue(Boolean newValue) {
+ mCurrentValue = newValue;
+ }
+
+ @Override
+ public String getStringValue() {
+ return mCurrentValue.toString();
+ }
+
+ @Override
+ public String toString() {
+ return getType() + "=" + getStringValue(); //$NON-NLS-1$
+ }
+
+ @Override
+ public void setValue(Object value) {
+ if (value instanceof Boolean) {
+ mCurrentValue = (Boolean) value;
+ } else {
+ throw new IllegalArgumentException("Attempt to set non-boolean value for " //$NON-NLS-1$
+ + getType());
+ }
+ }
+
+ @Override
+ public Object getValue() {
+ return mCurrentValue;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLCompositeProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLCompositeProperty.java
new file mode 100644
index 000000000..ff8b83a86
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLCompositeProperty.java
@@ -0,0 +1,136 @@
+/*
+ * 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.state;
+
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.Map;
+
+/**
+ * A composite property is a container for multiple named properties, kind of like a dictionary.
+ */
+public class GLCompositeProperty implements IGLProperty {
+ private final GLStateType mType;
+ private final Map<GLStateType, IGLProperty> mPropertiesMap;
+ private IGLProperty mParent;
+
+ /** Construct a composite property given a list of {@link IGLProperty} objects. */
+ public GLCompositeProperty(GLStateType type, IGLProperty... iglProperties) {
+ mType = type;
+ mPropertiesMap = new EnumMap<GLStateType, IGLProperty>(GLStateType.class);
+
+ for (IGLProperty p : iglProperties) {
+ mPropertiesMap.put(p.getType(), p);
+ p.setParent(this);
+ }
+ }
+
+ public Collection<IGLProperty> getProperties() {
+ return mPropertiesMap.values();
+ }
+
+ public IGLProperty getProperty(GLStateType name) {
+ return mPropertiesMap.get(name);
+ }
+
+ @Override
+ public GLCompositeProperty clone() {
+ IGLProperty []props = new IGLProperty[mPropertiesMap.size()];
+
+ int i = 0;
+ for (IGLProperty p : mPropertiesMap.values()) {
+ props[i++] = p.clone();
+ }
+
+ return new GLCompositeProperty(getType(), props);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("GLCompositeProperty {"); //$NON-NLS-1$
+
+ for (IGLProperty p : mPropertiesMap.values()) {
+ sb.append(p.toString());
+ sb.append(", "); //$NON-NLS-1$
+ }
+
+ sb.append("}");
+ return sb.toString();
+ }
+
+ @Override
+ public String getStringValue() {
+ // This method is called for displaying objects in the UI.
+ // We do not display any values for composites in the UI as they are only intermediate
+ // nodes in the tree.
+ return "";
+ }
+
+ @Override
+ public GLStateType getType() {
+ return mType;
+ }
+
+ @Override
+ public boolean isComposite() {
+ return true;
+ }
+
+ @Override
+ public boolean isDefault() {
+ for (IGLProperty p : mPropertiesMap.values()) {
+ if (!p.isDefault()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public IGLProperty getParent() {
+ return mParent;
+ }
+
+ @Override
+ public void setParent(IGLProperty parent) {
+ mParent = parent;
+ }
+
+ @Override
+ public void setValue(Object value) {
+ throw new UnsupportedOperationException(
+ "Values cannot be set for composite properties."); //$NON-NLS-1$
+ }
+
+ @Override
+ public Object getValue() {
+ throw new UnsupportedOperationException(
+ "Values cannot be obtained for composite properties."); //$NON-NLS-1$
+ }
+
+ @Override
+ public void prettyPrint(StatePrettyPrinter pp) {
+ pp.prettyPrint(mType, null);
+ pp.incrementIndentLevel();
+ for (IGLProperty p : mPropertiesMap.values()) {
+ p.prettyPrint(pp);
+ }
+ pp.decrementIndentLevel();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLEnumProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLEnumProperty.java
new file mode 100644
index 000000000..a3acbd4c8
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLEnumProperty.java
@@ -0,0 +1,64 @@
+/*
+ * 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.state;
+
+import com.android.ide.eclipse.gltrace.GLEnum;
+
+/** Properties that hold a {@link GLEnum}. */
+public final class GLEnumProperty extends GLAbstractAtomicProperty {
+ private GLEnum mCurrentValue;
+ private final GLEnum mDefaultValue;
+
+ public GLEnumProperty(GLStateType name, GLEnum defaultValue) {
+ super(name);
+
+ mCurrentValue = mDefaultValue = defaultValue;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return mDefaultValue == mCurrentValue;
+ }
+
+ public void setValue(GLEnum newValue) {
+ mCurrentValue = newValue;
+ }
+
+ @Override
+ public String getStringValue() {
+ return mCurrentValue.toString();
+ }
+
+ @Override
+ public String toString() {
+ return getType() + "=" + getStringValue(); //$NON-NLS-1$
+ }
+
+ @Override
+ public void setValue(Object value) {
+ if (value instanceof GLEnum) {
+ mCurrentValue = (GLEnum) value;
+ } else {
+ throw new IllegalArgumentException("Attempt to set invalid value for " + getType()); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Object getValue() {
+ return mCurrentValue;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLFloatProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLFloatProperty.java
new file mode 100644
index 000000000..387a88c6d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLFloatProperty.java
@@ -0,0 +1,63 @@
+/*
+ * 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.state;
+
+/** Properties that hold float values. */
+public class GLFloatProperty extends GLAbstractAtomicProperty {
+ private final Float mDefaultValue;
+ private Float mCurrentValue;
+
+ public GLFloatProperty(GLStateType name, Float defaultValue) {
+ super(name);
+
+ mDefaultValue = mCurrentValue = defaultValue;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return Math.abs(mCurrentValue - mDefaultValue) < 0.000000001;
+ }
+
+ public void setValue(Float newValue) {
+ mCurrentValue = newValue;
+ }
+
+ @Override
+ public void setValue(Object value) {
+ if (value instanceof Float) {
+ mCurrentValue = (Float) value;
+ } else {
+ throw new IllegalArgumentException("Attempt to set non float value for "
+ + getType());
+ }
+ }
+
+ @Override
+ public Object getValue() {
+ return mCurrentValue;
+ }
+
+ @Override
+ public String getStringValue() {
+ return mCurrentValue.toString();
+ }
+
+ @Override
+ public String toString() {
+ return getType() + "=" + getStringValue(); //$NON-NLS-1$
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLIntegerProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLIntegerProperty.java
new file mode 100644
index 000000000..7374ff087
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLIntegerProperty.java
@@ -0,0 +1,73 @@
+/*
+ * 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.state;
+
+/** Properties that hold an integer value. */
+public class GLIntegerProperty extends GLAbstractAtomicProperty {
+ private final Integer mDefaultValue;
+ private Integer mCurrentValue;
+ private final DisplayRadix mRadix;
+
+ public GLIntegerProperty(GLStateType name, Integer defaultValue, DisplayRadix radix) {
+ super(name);
+
+ mDefaultValue = mCurrentValue = defaultValue;
+ mRadix = radix;
+ }
+
+ public GLIntegerProperty(GLStateType name, Integer defaultValue) {
+ this(name, defaultValue, DisplayRadix.DECIMAL);
+ }
+
+ @Override
+ public boolean isDefault() {
+ return mDefaultValue != null & mDefaultValue.equals(mCurrentValue);
+ }
+
+ public void setValue(Integer newValue) {
+ mCurrentValue = newValue;
+ }
+
+ @Override
+ public String getStringValue() {
+ if (mRadix == DisplayRadix.HEX) {
+ return String.format("0x%08x", Integer.valueOf(mCurrentValue));
+ }
+
+ return mCurrentValue.toString();
+ }
+
+ @Override
+ public String toString() {
+ return getType() + "=" + getStringValue(); //$NON-NLS-1$
+ }
+
+ @Override
+ public void setValue(Object value) {
+ if (value instanceof Integer) {
+ mCurrentValue = (Integer) value;
+ } else {
+ throw new IllegalArgumentException("Attempt to set non-integer value for " //$NON-NLS-1$
+ + getType());
+ }
+ }
+
+ @Override
+ public Object getValue() {
+ return mCurrentValue;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLListProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLListProperty.java
new file mode 100644
index 000000000..6840abff4
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLListProperty.java
@@ -0,0 +1,182 @@
+/*
+ * 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.state;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * A list property is a container for a list of properties, addressed by index.
+ */
+public class GLListProperty implements IGLProperty {
+ private final List<IGLProperty> mList;
+ private final GLStateType mType;
+ private IGLProperty mParent;
+ private IGLProperty mTemplate;
+
+ /**
+ * Construct a list of properties of given size from the provided template.
+ * @param template property that will be cloned and used as members of the list
+ * @param size size of the list
+ */
+ public GLListProperty(GLStateType type, IGLProperty template, int size) {
+ mType = type;
+ mTemplate = template;
+
+ mList = new ArrayList<IGLProperty>(size);
+ for (int i = 0; i < size; i++) {
+ IGLProperty p = template.clone();
+ mList.add(p);
+
+ p.setParent(this);
+ }
+ }
+
+ private GLListProperty(GLStateType type, List<IGLProperty> props) {
+ mList = props;
+ mType = type;
+
+ for (IGLProperty p : mList) {
+ p.setParent(this);
+ }
+ }
+
+ public List<IGLProperty> getList() {
+ return mList;
+ }
+
+ public IGLProperty get(int index) {
+ return mList.get(index);
+ }
+
+ public boolean add(IGLProperty property) {
+ property.setParent(this);
+ return mList.add(property);
+ }
+
+ public boolean remove(IGLProperty property) {
+ return mList.remove(property);
+ }
+
+ public void set(int index, IGLProperty property) {
+ ensureCapacity(index + 1);
+ mList.set(index, property);
+ property.setParent(this);
+ }
+
+ private void ensureCapacity(int capactiy) {
+ for (int i = mList.size(); i < capactiy; i++) {
+ mList.add(mTemplate);
+ }
+ }
+
+ @Override
+ public GLListProperty clone() {
+ List<IGLProperty> props = new ArrayList<IGLProperty>(
+ mList.size());
+
+ for (IGLProperty p : mList) {
+ props.add(p.clone());
+ }
+
+ return new GLListProperty(getType(), props);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("GLListProperty ["); //$NON-NLS-1$
+
+ int i = 0;
+ for (IGLProperty p : mList) {
+ sb.append(i);
+ sb.append(':');
+ sb.append(p.toString());
+ sb.append(", "); //$NON-NLS-1$
+ i++;
+ }
+
+ sb.append("]");
+ return sb.toString();
+ }
+
+ @Override
+ public String getStringValue() {
+ // This method is called for displaying objects in the UI.
+ // We do not display any values for composites in the UI as they are only intermediate
+ // nodes in the tree.
+ return "";
+ }
+
+ @Override
+ public GLStateType getType() {
+ return mType;
+ }
+
+ @Override
+ public boolean isComposite() {
+ return true;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return false;
+ }
+
+ @Override
+ public IGLProperty getParent() {
+ return mParent;
+ }
+
+ @Override
+ public void setParent(IGLProperty parent) {
+ mParent = parent;
+ }
+
+ public int indexOf(IGLProperty property) {
+ return mList.indexOf(property);
+ }
+
+ @Override
+ public void setValue(Object value) {
+ throw new UnsupportedOperationException(
+ "Values cannot be set for composite properties."); //$NON-NLS-1$
+ }
+
+ @Override
+ public Object getValue() {
+ throw new UnsupportedOperationException(
+ "Values cannot be obtained for composite properties."); //$NON-NLS-1$
+ }
+
+ public int size() {
+ return mList.size();
+ }
+
+ @Override
+ public void prettyPrint(StatePrettyPrinter pp) {
+ pp.prettyPrint(mType, null);
+ pp.incrementIndentLevel();
+ for (int i = 0; i < mList.size(); i++) {
+ pp.prettyPrint(String.format(Locale.US, "Index %d:", i));
+ IGLProperty p = mList.get(i);
+ p.prettyPrint(pp);
+ }
+ pp.decrementIndentLevel();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLLongProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLLongProperty.java
new file mode 100644
index 000000000..44c04ec57
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLLongProperty.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 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.state;
+
+/** Properties that hold a long value. */
+public class GLLongProperty extends GLAbstractAtomicProperty {
+ private final Long mDefaultValue;
+ private Long mCurrentValue;
+ private final DisplayRadix mRadix;
+
+ public GLLongProperty(GLStateType name, Long defaultValue, DisplayRadix radix) {
+ super(name);
+
+ mDefaultValue = mCurrentValue = defaultValue;
+ mRadix = radix;
+ }
+
+ public GLLongProperty(GLStateType name, Long defaultValue) {
+ this(name, defaultValue, DisplayRadix.DECIMAL);
+ }
+
+ @Override
+ public boolean isDefault() {
+ return mDefaultValue != null & mDefaultValue.equals(mCurrentValue);
+ }
+
+ public void setValue(Long newValue) {
+ mCurrentValue = newValue;
+ }
+
+ @Override
+ public String getStringValue() {
+ if (mRadix == DisplayRadix.HEX) {
+ return String.format("0x%08x", Long.valueOf(mCurrentValue));
+ }
+
+ return mCurrentValue.toString();
+ }
+
+ @Override
+ public String toString() {
+ return getType() + "=" + getStringValue(); //$NON-NLS-1$
+ }
+
+ @Override
+ public void setValue(Object value) {
+ if (value instanceof Long) {
+ mCurrentValue = (Long) value;
+ } else {
+ throw new IllegalArgumentException("Attempt to set non-integer value for " //$NON-NLS-1$
+ + getType());
+ }
+ }
+
+ @Override
+ public Object getValue() {
+ return mCurrentValue;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLObjectProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLObjectProperty.java
new file mode 100644
index 000000000..703d4da6b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLObjectProperty.java
@@ -0,0 +1,66 @@
+/*
+ * 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.state;
+
+import com.google.common.base.Joiner;
+
+import java.util.List;
+
+public class GLObjectProperty extends GLAbstractAtomicProperty {
+ private final Object mDefaultValue;
+ private Object mCurrentValue;
+
+ private static final Joiner JOINER = Joiner.on(", "); //$NON-NLS-1$
+
+ public GLObjectProperty(GLStateType type, Object defaultValue) {
+ super(type);
+
+ mDefaultValue = mCurrentValue = defaultValue;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return mDefaultValue != null & mDefaultValue.equals(mCurrentValue);
+ }
+
+ @Override
+ public void setValue(Object newValue) {
+ mCurrentValue = newValue;
+ }
+
+ @Override
+ public String getStringValue() {
+ if (mCurrentValue == null) {
+ return "null";
+ } else {
+ if (mCurrentValue instanceof List<?>) {
+ return "[" + JOINER.join((List<?>) mCurrentValue) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return mCurrentValue.toString();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getType() + "=" + getStringValue(); //$NON-NLS-1$
+ }
+
+ @Override
+ public Object getValue() {
+ return mCurrentValue;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLSparseArrayProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLSparseArrayProperty.java
new file mode 100644
index 000000000..c45002857
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLSparseArrayProperty.java
@@ -0,0 +1,170 @@
+/*
+ * 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.state;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import com.android.utils.SparseArray;
+
+public class GLSparseArrayProperty implements IGLProperty {
+ private final GLStateType mType;
+ private final IGLProperty mDefaultValue;
+ private final boolean mCreateOnAccess;
+ private final SparseArray<IGLProperty> mSparseArray;
+ private IGLProperty mParent;
+
+ public GLSparseArrayProperty(GLStateType type, IGLProperty defaultValue) {
+ this(type, defaultValue, false);
+ }
+
+ /**
+ * Constructs a sparse array property.
+ * @param type GL state corresponding to this property
+ * @param defaultValue default value of each item
+ * @param createOnAccess create an item on access if it is not present
+ */
+ public GLSparseArrayProperty(GLStateType type, IGLProperty defaultValue,
+ boolean createOnAccess) {
+ mType = type;
+ mDefaultValue = defaultValue;
+ mCreateOnAccess = createOnAccess;
+ mSparseArray = new SparseArray<IGLProperty>(20);
+ }
+
+ private GLSparseArrayProperty(GLStateType type, IGLProperty defaultValue,
+ boolean createOnAccess, SparseArray<IGLProperty> contents) {
+ mType = type;
+ mDefaultValue = defaultValue;
+ mCreateOnAccess = createOnAccess;
+ mSparseArray = contents;
+ }
+
+ public List<IGLProperty> getValues() {
+ List<IGLProperty> values = new ArrayList<IGLProperty>(mSparseArray.size());
+
+ for (int i = 0; i < mSparseArray.size(); i++) {
+ values.add(mSparseArray.valueAt(i));
+ }
+
+ return values;
+ }
+
+ public IGLProperty getProperty(int key) {
+ IGLProperty p = mSparseArray.get(key);
+ if (p == null && mCreateOnAccess) {
+ add(key);
+ p = mSparseArray.get(key);
+ }
+ return p;
+ }
+
+ public int keyFor(IGLProperty element) {
+ int index = mSparseArray.indexOfValue(element);
+ return mSparseArray.keyAt(index);
+ }
+
+ public void put(int key, IGLProperty element) {
+ element.setParent(this);
+ mSparseArray.put(key, element);
+ }
+
+ public void add(int key) {
+ IGLProperty prop = mDefaultValue.clone();
+ prop.setParent(this);
+ mSparseArray.put(key, prop);
+ }
+
+ public void delete(int key) {
+ mSparseArray.delete(key);
+ }
+
+ @Override
+ public GLStateType getType() {
+ return mType;
+ }
+
+ @Override
+ public boolean isComposite() {
+ return true;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return false;
+ }
+
+ @Override
+ public IGLProperty getParent() {
+ return mParent;
+ }
+
+ @Override
+ public void setParent(IGLProperty parent) {
+ mParent = parent;
+ }
+
+ @Override
+ public GLSparseArrayProperty clone() {
+ SparseArray<IGLProperty> copy = new SparseArray<IGLProperty>(mSparseArray.size());
+ for (int i = 0; i < mSparseArray.size(); i++) {
+ int key = mSparseArray.keyAt(i);
+ IGLProperty value = mSparseArray.get(key);
+ copy.put(key, value);
+ }
+
+ return new GLSparseArrayProperty(mType, mDefaultValue, mCreateOnAccess, copy);
+ }
+
+ @Override
+ public String getStringValue() {
+ // This method is called for displaying objects in the UI.
+ // We do not display any values for composites in the UI as they are only intermediate
+ // nodes in the tree.
+ return "";
+ }
+
+ @Override
+ public void setValue(Object value) {
+ throw new UnsupportedOperationException(
+ "Values cannot be set for composite properties."); //$NON-NLS-1$
+ }
+
+ @Override
+ public Object getValue() {
+ throw new UnsupportedOperationException(
+ "Values cannot be obtained for composite properties."); //$NON-NLS-1$
+ }
+
+ @Override
+ public void prettyPrint(StatePrettyPrinter pp) {
+ pp.prettyPrint(mType, null);
+ pp.incrementIndentLevel();
+ for (int i = 0; i < mSparseArray.size(); i++) {
+ int key = mSparseArray.keyAt(i);
+ pp.prettyPrint(String.format(Locale.US, "Index %d:", key));
+ IGLProperty prop = mSparseArray.get(key);
+
+ assert prop != null;
+ if (prop != null) {
+ prop.prettyPrint(pp);
+ }
+ }
+ pp.decrementIndentLevel();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLState.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLState.java
new file mode 100644
index 000000000..04ce676c2
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLState.java
@@ -0,0 +1,402 @@
+/*
+ * 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.state;
+
+import com.android.ide.eclipse.gltrace.GLEnum;
+import com.android.ide.eclipse.gltrace.state.DisplayRadix;
+
+import java.util.Collections;
+
+public class GLState {
+ /** # of texture units modeled in the GL State. */
+ public static final int TEXTURE_UNIT_COUNT = 32;
+
+ /** # of vertex attributes */
+ private static final int MAX_VERTEX_ATTRIBS = 16;
+
+ private static GLState sGLState = new GLState();
+
+ private IGLProperty createBufferBindings() {
+ IGLProperty array, eArray, vArray;
+
+ array = new GLIntegerProperty(GLStateType.ARRAY_BUFFER_BINDING, 0);
+ eArray = new GLIntegerProperty(GLStateType.ELEMENT_ARRAY_BUFFER_BINDING, 0);
+
+ vArray = new GLIntegerProperty(
+ GLStateType.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_PER_INDEX, 0);
+ IGLProperty vArray8 = new GLListProperty(GLStateType.VERTEX_ATTRIB_ARRAY_BUFFER_BINDINGS,
+ vArray, MAX_VERTEX_ATTRIBS);
+
+ return new GLCompositeProperty(
+ GLStateType.BUFFER_BINDINGS,
+ array,
+ eArray,
+ vArray8);
+ }
+
+ private IGLProperty createVertexAttribArrays() {
+ IGLProperty enabled, size, stride, type, normalized, pointer;
+
+ enabled = new GLBooleanProperty(GLStateType.VERTEX_ATTRIB_ARRAY_ENABLED, false);
+ size = new GLIntegerProperty(GLStateType.VERTEX_ATTRIB_ARRAY_SIZE, 4);
+ stride = new GLIntegerProperty(GLStateType.VERTEX_ATTRIB_ARRAY_STRIDE, 0);
+ type = new GLEnumProperty(GLStateType.VERTEX_ATTRIB_ARRAY_TYPE, GLEnum.GL_FLOAT);
+ normalized = new GLBooleanProperty(GLStateType.VERTEX_ATTRIB_ARRAY_NORMALIZED, false);
+ pointer = new GLLongProperty(GLStateType.VERTEX_ATTRIB_ARRAY_POINTER, 0L,
+ DisplayRadix.HEX);
+
+ IGLProperty perVertexAttribArrayState = new GLCompositeProperty(
+ GLStateType.VERTEX_ATTRIB_ARRAY_COMPOSITE,
+ enabled,
+ size,
+ stride,
+ type,
+ normalized,
+ pointer);
+
+ return new GLListProperty(
+ GLStateType.VERTEX_ATTRIB_ARRAY,
+ perVertexAttribArrayState,
+ MAX_VERTEX_ATTRIBS);
+ }
+
+ private IGLProperty createGenericVertexAttributeState() {
+ IGLProperty v0 = new GLFloatProperty(GLStateType.GENERIC_VERTEX_ATTRIB_V0,
+ Float.valueOf(0));
+ IGLProperty v1 = new GLFloatProperty(GLStateType.GENERIC_VERTEX_ATTRIB_V1,
+ Float.valueOf(0));
+ IGLProperty v2 = new GLFloatProperty(GLStateType.GENERIC_VERTEX_ATTRIB_V2,
+ Float.valueOf(0));
+ IGLProperty v3 = new GLFloatProperty(GLStateType.GENERIC_VERTEX_ATTRIB_V3,
+ Float.valueOf(0));
+
+ IGLProperty perGenericVertexAttribState = new GLCompositeProperty(
+ GLStateType.GENERIC_VERTEX_ATTRIBUTE_DATA_COMPOSITE,
+ v0, v1, v2, v3);
+
+ return new GLListProperty(
+ GLStateType.GENERIC_VERTEX_ATTRIBUTES,
+ perGenericVertexAttribState,
+ MAX_VERTEX_ATTRIBS);
+ }
+
+ private IGLProperty createVboState() {
+ IGLProperty size = new GLIntegerProperty(GLStateType.BUFFER_SIZE, Integer.valueOf(0));
+ IGLProperty usage = new GLEnumProperty(GLStateType.BUFFER_USAGE, GLEnum.GL_STATIC_DRAW);
+ IGLProperty data = new GLObjectProperty(GLStateType.BUFFER_DATA, new byte[0]);
+ IGLProperty type = new GLEnumProperty(GLStateType.BUFFER_TYPE, GLEnum.GL_ARRAY_BUFFER);
+
+ IGLProperty perVboState = new GLCompositeProperty(GLStateType.VBO_COMPOSITE,
+ size, usage, data, type);
+
+ return new GLSparseArrayProperty(GLStateType.VBO, perVboState);
+ }
+
+ private IGLProperty createVertexArrayData() {
+ IGLProperty vertexAttribArrays = createVertexAttribArrays();
+ IGLProperty bufferBindings = createBufferBindings();
+ IGLProperty genericAttribs = createGenericVertexAttributeState();
+ IGLProperty vboState = createVboState();
+
+ return new GLCompositeProperty(GLStateType.VERTEX_ARRAY_DATA,
+ genericAttribs,
+ vertexAttribArrays,
+ bufferBindings,
+ vboState);
+ }
+
+ private IGLProperty createTransformationState() {
+ IGLProperty viewPortX = new GLIntegerProperty(GLStateType.VIEWPORT_X, 0);
+ IGLProperty viewPortY = new GLIntegerProperty(GLStateType.VIEWPORT_Y, 0);
+ IGLProperty viewPortW = new GLIntegerProperty(GLStateType.VIEWPORT_WIDTH, 0);
+ IGLProperty viewPortH = new GLIntegerProperty(GLStateType.VIEWPORT_HEIGHT, 0);
+ IGLProperty viewPort = new GLCompositeProperty(GLStateType.VIEWPORT,
+ viewPortX, viewPortY, viewPortW, viewPortH);
+
+ IGLProperty clampNear = new GLFloatProperty(GLStateType.DEPTH_RANGE_NEAR,
+ Float.valueOf(0.0f));
+ IGLProperty clampFar = new GLFloatProperty(GLStateType.DEPTH_RANGE_FAR,
+ Float.valueOf(1.0f));
+ IGLProperty depthRange = new GLCompositeProperty(GLStateType.DEPTH_RANGE,
+ clampNear,
+ clampFar);
+
+ IGLProperty transformationState = new GLCompositeProperty(GLStateType.TRANSFORMATION_STATE,
+ viewPort,
+ depthRange);
+ return transformationState;
+ }
+
+ private IGLProperty createRasterizationState() {
+ IGLProperty lineWidth = new GLFloatProperty(GLStateType.LINE_WIDTH, Float.valueOf(1.0f));
+ IGLProperty cullFace = new GLBooleanProperty(GLStateType.CULL_FACE, Boolean.FALSE);
+ IGLProperty cullFaceMode = new GLEnumProperty(GLStateType.CULL_FACE_MODE, GLEnum.GL_BACK);
+ IGLProperty frontFace = new GLEnumProperty(GLStateType.FRONT_FACE, GLEnum.GL_CCW);
+ IGLProperty polyOffsetFactor = new GLFloatProperty(GLStateType.POLYGON_OFFSET_FACTOR,
+ Float.valueOf(0f));
+ IGLProperty polyOffsetUnits = new GLFloatProperty(GLStateType.POLYGON_OFFSET_UNITS,
+ Float.valueOf(0f));
+ IGLProperty polyOffsetFill = new GLBooleanProperty(GLStateType.POLYGON_OFFSET_FILL,
+ Boolean.FALSE);
+
+ return new GLCompositeProperty(GLStateType.RASTERIZATION_STATE,
+ lineWidth,
+ cullFace,
+ cullFaceMode,
+ frontFace,
+ polyOffsetFactor,
+ polyOffsetUnits,
+ polyOffsetFill);
+ }
+
+ private IGLProperty createPixelOperationsState() {
+ IGLProperty scissorTest = new GLBooleanProperty(GLStateType.SCISSOR_TEST, Boolean.FALSE);
+ IGLProperty scissorBoxX = new GLIntegerProperty(GLStateType.SCISSOR_BOX_X, 0);
+ IGLProperty scissorBoxY = new GLIntegerProperty(GLStateType.SCISSOR_BOX_Y, 0);
+ IGLProperty scissorBoxW = new GLIntegerProperty(GLStateType.SCISSOR_BOX_WIDTH, 0);
+ IGLProperty scissorBoxH = new GLIntegerProperty(GLStateType.SCISSOR_BOX_HEIGHT, 0);
+ IGLProperty scissorBox = new GLCompositeProperty(GLStateType.SCISSOR_BOX,
+ scissorBoxX, scissorBoxY, scissorBoxW, scissorBoxH);
+
+ IGLProperty stencilTest = new GLBooleanProperty(GLStateType.STENCIL_TEST, Boolean.FALSE);
+ IGLProperty stencilFunc = new GLEnumProperty(GLStateType.STENCIL_FUNC, GLEnum.GL_ALWAYS);
+ IGLProperty stencilMask = new GLIntegerProperty(GLStateType.STENCIL_VALUE_MASK,
+ Integer.valueOf(0xffffffff), DisplayRadix.HEX);
+ IGLProperty stencilRef = new GLIntegerProperty(GLStateType.STENCIL_REF,
+ Integer.valueOf(0));
+ IGLProperty stencilFail = new GLEnumProperty(GLStateType.STENCIL_FAIL, GLEnum.GL_KEEP);
+ IGLProperty stencilPassDepthFail = new GLEnumProperty(GLStateType.STENCIL_PASS_DEPTH_FAIL,
+ GLEnum.GL_KEEP);
+ IGLProperty stencilPassDepthPass = new GLEnumProperty(GLStateType.STENCIL_PASS_DEPTH_PASS,
+ GLEnum.GL_KEEP);
+ IGLProperty stencilBackFunc = new GLEnumProperty(GLStateType.STENCIL_BACK_FUNC,
+ GLEnum.GL_ALWAYS);
+ IGLProperty stencilBackValueMask = new GLIntegerProperty(
+ GLStateType.STENCIL_BACK_VALUE_MASK, Integer.valueOf(0xffffffff), DisplayRadix.HEX);
+ IGLProperty stencilBackRef = new GLIntegerProperty(GLStateType.STENCIL_BACK_REF, 0);
+ IGLProperty stencilBackFail = new GLEnumProperty(GLStateType.STENCIL_BACK_FAIL,
+ GLEnum.GL_KEEP);
+ IGLProperty stencilBackPassDepthFail = new GLEnumProperty(
+ GLStateType.STENCIL_BACK_PASS_DEPTH_FAIL, GLEnum.GL_KEEP);
+ IGLProperty stencilBackPassDepthPass = new GLEnumProperty(
+ GLStateType.STENCIL_BACK_PASS_DEPTH_PASS, GLEnum.GL_KEEP);
+ IGLProperty stencil = new GLCompositeProperty(GLStateType.STENCIL,
+ stencilTest, stencilFunc,
+ stencilMask, stencilRef, stencilFail,
+ stencilPassDepthFail, stencilPassDepthPass,
+ stencilBackFunc, stencilBackValueMask,
+ stencilBackRef, stencilBackFail,
+ stencilBackPassDepthFail, stencilBackPassDepthPass);
+
+ IGLProperty depthTest = new GLBooleanProperty(GLStateType.DEPTH_TEST, Boolean.FALSE);
+ IGLProperty depthFunc = new GLEnumProperty(GLStateType.DEPTH_FUNC, GLEnum.GL_LESS);
+
+ IGLProperty blendEnabled = new GLBooleanProperty(GLStateType.BLEND_ENABLED, Boolean.FALSE);
+ // FIXME: BLEND_SRC_RGB should be set to GL_ONE, but GL_LINES is already 0x1.
+ IGLProperty blendSrcRgb = new GLEnumProperty(GLStateType.BLEND_SRC_RGB, GLEnum.GL_LINES);
+ IGLProperty blendSrcAlpha = new GLEnumProperty(GLStateType.BLEND_SRC_ALPHA,
+ GLEnum.GL_LINES);
+ IGLProperty blendDstRgb = new GLEnumProperty(GLStateType.BLEND_DST_RGB, GLEnum.GL_NONE);
+ IGLProperty blendDstAlpha = new GLEnumProperty(GLStateType.BLEND_DST_ALPHA,
+ GLEnum.GL_NONE);
+ IGLProperty blendEquationRgb = new GLEnumProperty(GLStateType.BLEND_EQUATION_RGB,
+ GLEnum.GL_FUNC_ADD);
+ IGLProperty blendEquationAlpha = new GLEnumProperty(GLStateType.BLEND_EQUATION_ALPHA,
+ GLEnum.GL_FUNC_ADD);
+ IGLProperty blend = new GLCompositeProperty(GLStateType.BLEND,
+ blendEnabled, blendSrcRgb, blendSrcAlpha, blendDstRgb, blendDstAlpha,
+ blendEquationRgb, blendEquationAlpha);
+
+ IGLProperty dither = new GLBooleanProperty(GLStateType.DITHER, Boolean.TRUE);
+
+ return new GLCompositeProperty(GLStateType.PIXEL_OPERATIONS,
+ scissorTest, scissorBox, stencil,
+ depthTest, depthFunc, blend, dither);
+ }
+
+ private IGLProperty createPixelPackState() {
+ IGLProperty packAlignment = new GLIntegerProperty(GLStateType.PACK_ALIGNMENT,
+ Integer.valueOf(4));
+ IGLProperty unpackAlignment = new GLIntegerProperty(GLStateType.UNPACK_ALIGNMENT,
+ Integer.valueOf(4));
+ IGLProperty pixelPack = new GLCompositeProperty(GLStateType.PIXEL_PACKING,
+ packAlignment, unpackAlignment);
+ return pixelPack;
+ }
+
+ private IGLProperty createFramebufferState() {
+ IGLProperty binding = new GLIntegerProperty(GLStateType.FRAMEBUFFER_BINDING, 0);
+ GLCompositeProperty framebufferState = new GLCompositeProperty(
+ GLStateType.FRAMEBUFFER_STATE,
+ binding);
+ return framebufferState;
+ }
+
+ private IGLProperty createTextureState() {
+ IGLProperty activeTexture = new GLIntegerProperty(GLStateType.ACTIVE_TEXTURE_UNIT,
+ Integer.valueOf(0));
+
+ IGLProperty binding2D = new GLIntegerProperty(GLStateType.TEXTURE_BINDING_2D,
+ Integer.valueOf(0));
+ IGLProperty bindingCubeMap = new GLIntegerProperty(GLStateType.TEXTURE_BINDING_CUBE_MAP,
+ Integer.valueOf(0));
+ IGLProperty bindingExternal = new GLIntegerProperty(GLStateType.TEXTURE_BINDING_EXTERNAL,
+ Integer.valueOf(0));
+ IGLProperty perTextureUnitState = new GLCompositeProperty(
+ GLStateType.PER_TEXTURE_UNIT_STATE, binding2D, bindingCubeMap, bindingExternal);
+ IGLProperty textureUnitState = new GLListProperty(GLStateType.TEXTURE_UNITS,
+ perTextureUnitState, TEXTURE_UNIT_COUNT);
+
+ IGLProperty swizzleR = new GLEnumProperty(GLStateType.TEXTURE_SWIZZLE_R, GLEnum.GL_RED);
+ IGLProperty swizzleG = new GLEnumProperty(GLStateType.TEXTURE_SWIZZLE_G, GLEnum.GL_GREEN);
+ IGLProperty swizzleB = new GLEnumProperty(GLStateType.TEXTURE_SWIZZLE_B, GLEnum.GL_BLUE);
+ IGLProperty swizzleA = new GLEnumProperty(GLStateType.TEXTURE_SWIZZLE_A, GLEnum.GL_ALPHA);
+ IGLProperty minFilter = new GLEnumProperty(GLStateType.TEXTURE_MIN_FILTER,
+ GLEnum.GL_NEAREST);
+ IGLProperty magFilter = new GLEnumProperty(GLStateType.TEXTURE_MAG_FILTER,
+ GLEnum.GL_NEAREST);
+ IGLProperty wrapS = new GLEnumProperty(GLStateType.TEXTURE_WRAP_S, GLEnum.GL_REPEAT);
+ IGLProperty wrapT = new GLEnumProperty(GLStateType.TEXTURE_WRAP_T, GLEnum.GL_REPEAT);
+ IGLProperty wrapR = new GLEnumProperty(GLStateType.TEXTURE_WRAP_R, GLEnum.GL_REPEAT);
+ IGLProperty minLod = new GLFloatProperty(GLStateType.TEXTURE_MIN_LOD, Float.valueOf(-1000));
+ IGLProperty maxLod = new GLFloatProperty(GLStateType.TEXTURE_MAX_LOD, Float.valueOf(1000));
+ IGLProperty baseLevel = new GLIntegerProperty(GLStateType.TEXTURE_BASE_LEVEL, 0);
+ IGLProperty maxLevel = new GLIntegerProperty(GLStateType.TEXTURE_MAX_LEVEL, 1000);
+ IGLProperty cmpMode = new GLEnumProperty(GLStateType.TEXTURE_COMPARE_MODE, GLEnum.GL_NONE);
+ IGLProperty cmpFunc = new GLEnumProperty(GLStateType.TEXTURE_COMPARE_FUNC,
+ GLEnum.GL_LEQUAL);
+ IGLProperty immutableFormat = new GLBooleanProperty(GLStateType.TEXTURE_IMMUTABLE_FORMAT,
+ Boolean.FALSE);
+ IGLProperty immutableLevels = new GLIntegerProperty(GLStateType.TEXTURE_IMMUTABLE_LEVELS,
+ 0);
+
+ IGLProperty width = new GLIntegerProperty(GLStateType.TEXTURE_WIDTH, Integer.valueOf(-1));
+ IGLProperty height = new GLIntegerProperty(GLStateType.TEXTURE_HEIGHT,
+ Integer.valueOf(-1));
+ IGLProperty format = new GLEnumProperty(GLStateType.TEXTURE_FORMAT,
+ GLEnum.GL_INVALID_VALUE);
+ IGLProperty imageType = new GLEnumProperty(GLStateType.TEXTURE_IMAGE_TYPE,
+ GLEnum.GL_UNSIGNED_BYTE);
+ IGLProperty image = new GLStringProperty(GLStateType.TEXTURE_IMAGE, null);
+
+ IGLProperty perTextureLevelState = new GLCompositeProperty(
+ GLStateType.PER_TEXTURE_LEVEL_STATE,
+ width, height, format, imageType, image);
+ IGLProperty mipmapState = new GLSparseArrayProperty(GLStateType.TEXTURE_MIPMAPS,
+ perTextureLevelState, true);
+
+ IGLProperty textureDefaultState = new GLCompositeProperty(GLStateType.PER_TEXTURE_STATE,
+ swizzleR, swizzleG, swizzleB, swizzleA,
+ minFilter, magFilter,
+ wrapS, wrapT, wrapR,
+ minLod, maxLod,
+ baseLevel, maxLevel,
+ cmpMode, cmpFunc,
+ immutableFormat, immutableLevels,
+ mipmapState);
+ GLSparseArrayProperty textures = new GLSparseArrayProperty(GLStateType.TEXTURES,
+ textureDefaultState);
+ textures.add(0);
+
+ return new GLCompositeProperty(GLStateType.TEXTURE_STATE,
+ activeTexture,
+ textureUnitState,
+ textures);
+ }
+
+ private IGLProperty createProgramState() {
+ IGLProperty currentProgram = new GLIntegerProperty(GLStateType.CURRENT_PROGRAM,
+ Integer.valueOf(0));
+
+ IGLProperty attachedShaderId = new GLIntegerProperty(GLStateType.ATTACHED_SHADER_ID,
+ Integer.valueOf(0));
+ IGLProperty attachedShaders = new GLSparseArrayProperty(GLStateType.ATTACHED_SHADERS,
+ attachedShaderId);
+
+ IGLProperty attributeName = new GLStringProperty(GLStateType.ATTRIBUTE_NAME, "");
+ IGLProperty attributeType = new GLEnumProperty(GLStateType.ATTRIBUTE_TYPE,
+ GLEnum.GL_FLOAT_MAT4);
+ IGLProperty attributeSize = new GLIntegerProperty(GLStateType.ATTRIBUTE_SIZE,
+ Integer.valueOf(1));
+ IGLProperty attributeValue = new GLObjectProperty(GLStateType.ATTRIBUTE_VALUE,
+ Collections.emptyList());
+ IGLProperty perAttributeProperty = new GLCompositeProperty(GLStateType.PER_ATTRIBUTE_STATE,
+ attributeName, attributeType, attributeSize, attributeValue);
+ IGLProperty attributes = new GLSparseArrayProperty(GLStateType.ACTIVE_ATTRIBUTES,
+ perAttributeProperty);
+
+ IGLProperty uniformName = new GLStringProperty(GLStateType.UNIFORM_NAME, "");
+ IGLProperty uniformType = new GLEnumProperty(GLStateType.UNIFORM_TYPE,
+ GLEnum.GL_FLOAT_MAT4);
+ IGLProperty uniformSize = new GLIntegerProperty(GLStateType.UNIFORM_SIZE,
+ Integer.valueOf(1));
+ IGLProperty uniformValue = new GLObjectProperty(GLStateType.UNIFORM_VALUE,
+ Collections.emptyList());
+ IGLProperty perUniformProperty = new GLCompositeProperty(GLStateType.PER_UNIFORM_STATE,
+ uniformName, uniformType, uniformSize, uniformValue);
+ IGLProperty uniforms = new GLSparseArrayProperty(GLStateType.ACTIVE_UNIFORMS,
+ perUniformProperty);
+
+ IGLProperty perProgramState = new GLCompositeProperty(GLStateType.PER_PROGRAM_STATE,
+ attachedShaders, attributes, uniforms);
+
+ IGLProperty programs = new GLSparseArrayProperty(GLStateType.PROGRAMS, perProgramState);
+
+ return new GLCompositeProperty(GLStateType.PROGRAM_STATE,
+ currentProgram, programs);
+ }
+
+ private IGLProperty createShaderState() {
+ IGLProperty shaderType = new GLEnumProperty(GLStateType.SHADER_TYPE,
+ GLEnum.GL_VERTEX_SHADER);
+ IGLProperty shaderSource = new GLStringProperty(GLStateType.SHADER_SOURCE,
+ ""); //$NON-NLS-1$
+ IGLProperty perShaderState = new GLCompositeProperty(GLStateType.PER_SHADER_STATE,
+ shaderType, shaderSource);
+ return new GLSparseArrayProperty(GLStateType.SHADERS, perShaderState);
+ }
+
+ public static IGLProperty createDefaultES2State() {
+ GLCompositeProperty glState = new GLCompositeProperty(GLStateType.GL_STATE_ES2,
+ sGLState.createVertexArrayData(),
+ sGLState.createFramebufferState(),
+ sGLState.createTransformationState(),
+ sGLState.createRasterizationState(),
+ sGLState.createPixelOperationsState(),
+ sGLState.createPixelPackState(),
+ sGLState.createTextureState(),
+ sGLState.createProgramState(),
+ sGLState.createShaderState());
+ return glState;
+ }
+
+ public static IGLProperty createDefaultES1State() {
+ GLCompositeProperty glState = new GLCompositeProperty(GLStateType.GL_STATE_ES1,
+ sGLState.createVertexArrayData(),
+ sGLState.createFramebufferState(),
+ sGLState.createTransformationState(),
+ sGLState.createRasterizationState(),
+ sGLState.createPixelOperationsState(),
+ sGLState.createPixelPackState(),
+ sGLState.createTextureState());
+ return glState;
+ }
+
+ public static IGLProperty createDefaultState() {
+ return new GLListProperty(GLStateType.GL_STATE, null, 0);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStateType.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStateType.java
new file mode 100644
index 000000000..a0a7ce470
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStateType.java
@@ -0,0 +1,187 @@
+/*
+ * 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.state;
+
+/** The type for each OpenGL State Property {@link IGLProperty}. */
+public enum GLStateType {
+ // Note: the indentation reflects the state hierarchy.
+
+ GL_STATE("OpenGL State Variables"),
+ GL_STATE_ES1("OpenGL ES 1.1 State"),
+ GL_STATE_ES2("OpenGL ES 2.0 State"),
+
+ VERTEX_ARRAY_DATA("Vertex Array Data"),
+ GENERIC_VERTEX_ATTRIBUTES("Generic Vertex Attributes"),
+ GENERIC_VERTEX_ATTRIBUTE_DATA_COMPOSITE("Generic Vertex Attribute Data"),
+ GENERIC_VERTEX_ATTRIB_V0("x"),
+ GENERIC_VERTEX_ATTRIB_V1("y"),
+ GENERIC_VERTEX_ATTRIB_V2("z"),
+ GENERIC_VERTEX_ATTRIB_V3("w"),
+
+ VERTEX_ATTRIB_ARRAY("Vertex Attrib Array Properties"),
+ VERTEX_ATTRIB_ARRAY_COMPOSITE("Vertex Attrib Array #n Properties"),
+ VERTEX_ATTRIB_ARRAY_ENABLED("Vertex Attrib Array Enable"),
+ VERTEX_ATTRIB_ARRAY_SIZE("Vertex Attrib Array Size"),
+ VERTEX_ATTRIB_ARRAY_STRIDE("Vertex Attrib Array Stride"),
+ VERTEX_ATTRIB_ARRAY_TYPE("Vertex Attrib Array Type"),
+ VERTEX_ATTRIB_ARRAY_NORMALIZED("Vertex Attrib Array Normalized"),
+ VERTEX_ATTRIB_ARRAY_POINTER("Vertex Attrib Array Pointer"),
+
+ BUFFER_BINDINGS("Buffer Bindings"),
+ ARRAY_BUFFER_BINDING("Current Buffer Binding"),
+ ELEMENT_ARRAY_BUFFER_BINDING("Element Array Buffer Binding"),
+ VERTEX_ATTRIB_ARRAY_BUFFER_BINDINGS("Attribute Array Buffer Bindings"),
+ VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_PER_INDEX("Attribute Array Buffer Binding"),
+
+ VBO("Vertex Buffer Objects"),
+ VBO_COMPOSITE("Per VBO State"),
+ BUFFER_SIZE("Size"),
+ BUFFER_USAGE("Usage"),
+ BUFFER_DATA("Data"),
+ BUFFER_TYPE("Type"),
+
+ TRANSFORMATION_STATE("Transformation State"),
+ VIEWPORT("Viewport"),
+ VIEWPORT_X("Lower Left X"),
+ VIEWPORT_Y("Lower Left Y"),
+ VIEWPORT_WIDTH("Width"),
+ VIEWPORT_HEIGHT("Height"),
+ DEPTH_RANGE("Depth Range"),
+ DEPTH_RANGE_NEAR("Near Clipping Plane"),
+ DEPTH_RANGE_FAR("Far Clipping Plane"),
+
+ RASTERIZATION_STATE("Rasterization State"),
+ LINE_WIDTH("Line Width"),
+ CULL_FACE("Polygon Culling Enabled"),
+ CULL_FACE_MODE("Cull front/back facing polygons"),
+ FRONT_FACE("Polygon frontface CW/CCW indicator"),
+ POLYGON_OFFSET_FACTOR("Polygon Offset Factor"),
+ POLYGON_OFFSET_UNITS("Polygon Offset Units"),
+ POLYGON_OFFSET_FILL("Polygon Offset Enable"),
+
+ PIXEL_OPERATIONS("Pixel Operations"),
+ SCISSOR_TEST("Scissoring enabled"),
+ SCISSOR_BOX("Scissor Box"),
+ SCISSOR_BOX_X("Lower Left X"),
+ SCISSOR_BOX_Y("Lower Left Y"),
+ SCISSOR_BOX_WIDTH("Width"),
+ SCISSOR_BOX_HEIGHT("Height"),
+ STENCIL("Stencil"),
+ STENCIL_TEST("Stenciling enabled"),
+ STENCIL_FUNC("Front Stencil Function"),
+ STENCIL_VALUE_MASK("Front Stencil Mask"),
+ STENCIL_REF("Front Stencil Reference Value"),
+ STENCIL_FAIL("Front Stencil Fail Action"),
+ STENCIL_PASS_DEPTH_FAIL("Front stencil depth buffer fail action"),
+ STENCIL_PASS_DEPTH_PASS("Front stencil depth buffer pass action"),
+ STENCIL_BACK_FUNC("Back stencil function"),
+ STENCIL_BACK_VALUE_MASK("Back stencil mask"),
+ STENCIL_BACK_REF("Back stencil reference value"),
+ STENCIL_BACK_FAIL("Back stencil fail action"),
+ STENCIL_BACK_PASS_DEPTH_FAIL("Back stencil depth buffer fail action"),
+ STENCIL_BACK_PASS_DEPTH_PASS("Back stencil depth buffer pass action"),
+ DEPTH_TEST("Depth buffer enabled"),
+ DEPTH_FUNC("Depth buffer test function"),
+ BLEND("Blending"),
+ BLEND_ENABLED("Enabled"),
+ BLEND_SRC_RGB("Source RGB function"),
+ BLEND_SRC_ALPHA("Source A function"),
+ BLEND_DST_RGB("Dest. RGB function"),
+ BLEND_DST_ALPHA("Dest. A function"),
+ BLEND_EQUATION_RGB("RGB Equation"),
+ BLEND_EQUATION_ALPHA("Alpha Equation"),
+ DITHER("Dithering enabled"),
+
+ PIXEL_PACKING("Pixel Packing"),
+ PACK_ALIGNMENT("Pack Alignment"),
+ UNPACK_ALIGNMENT("Unpack Alignment"),
+
+ TEXTURE_STATE("Texture State"),
+ ACTIVE_TEXTURE_UNIT("Active Texture Unit"),
+ TEXTURE_UNITS("Texture Units"),
+ PER_TEXTURE_UNIT_STATE("Texture Unit Properties"),
+ TEXTURE_BINDING_2D("TEXTURE_2D Binding"),
+ TEXTURE_BINDING_CUBE_MAP("TEXTURE_CUBE_MAP Binding"),
+ TEXTURE_BINDING_EXTERNAL("TEXTURE_EXTERNAL Binding"),
+ TEXTURES("Textures"),
+ PER_TEXTURE_STATE("Per Texture State"),
+ TEXTURE_SWIZZLE_R("Red Component Swizzle"),
+ TEXTURE_SWIZZLE_G("Green Component Swizzle"),
+ TEXTURE_SWIZZLE_B("Blue Component Swizzle"),
+ TEXTURE_SWIZZLE_A("Alpha Component Swizzle"),
+ TEXTURE_MIN_FILTER("Minification Function"),
+ TEXTURE_MAG_FILTER("Magnification Function"),
+ TEXTURE_WRAP_S("Texcoord s Wrap Mode"),
+ TEXTURE_WRAP_T("Texcoord t Wrap Mode"),
+ TEXTURE_WRAP_R("Texcoord r Wrap Mode"),
+ TEXTURE_MIN_LOD("Min Level of Detail"),
+ TEXTURE_MAX_LOD("Max Level of Detail"),
+ TEXTURE_BASE_LEVEL("Base Texture Array"),
+ TEXTURE_MAX_LEVEL("Max Texture Array Level"),
+ TEXTURE_COMPARE_MODE("Comparison Mode"),
+ TEXTURE_COMPARE_FUNC("Comparison Function"),
+ TEXTURE_IMMUTABLE_FORMAT("Size and format immutable?"),
+ TEXTURE_IMMUTABLE_LEVELS("# of levels in immutable textures"),
+ TEXTURE_MIPMAPS("Texture Mipmap State"),
+ PER_TEXTURE_LEVEL_STATE("Per Texture Level State"),
+ TEXTURE_FORMAT("Format"),
+ TEXTURE_WIDTH("Width"),
+ TEXTURE_HEIGHT("Height"),
+ TEXTURE_IMAGE_TYPE("Image Type"),
+ TEXTURE_IMAGE("Image"),
+
+ PROGRAM_STATE("Program Object State"),
+ CURRENT_PROGRAM("Current Program"),
+ PROGRAMS("Programs"),
+ PER_PROGRAM_STATE("Per Program State"),
+ ATTACHED_SHADERS("Attached Shaders"),
+ ATTACHED_SHADER_ID("Attached Shader ID"),
+ ACTIVE_ATTRIBUTES("Attributes"),
+ PER_ATTRIBUTE_STATE("Per Attribute State"),
+ ATTRIBUTE_NAME("Name"),
+ ATTRIBUTE_TYPE("Type"),
+ ATTRIBUTE_SIZE("Size"),
+ ATTRIBUTE_VALUE("Value"),
+ ACTIVE_UNIFORMS("Uniforms"),
+ PER_UNIFORM_STATE("Per Uniform State"),
+ UNIFORM_NAME("Name"),
+ UNIFORM_TYPE("Type"),
+ UNIFORM_SIZE("Size"),
+ UNIFORM_VALUE("Value"),
+
+ SHADERS("Shader Objects"),
+ PER_SHADER_STATE("Per Shader State"),
+ SHADER_TYPE("Shader Type"),
+ SHADER_SOURCE("Source"),
+
+ FRAMEBUFFER_STATE("Framebuffer State"),
+ FRAMEBUFFER_BINDING("Framebuffer Binding"),
+ FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE("Framebuffer object type"),
+ FRAMEBUFFER_ATTACHMENT_OBJECT_NAME("Framebuffer object name"),
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL("Framebuffer texture level"),
+ FRAMEBUFFER_ATTACHEMENT_TEXTURE_CUBE_MAP_FACE("Framebuffer texture cubemap face");
+
+ private final String mDescription;
+
+ GLStateType(String description) {
+ mDescription = description;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStringProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStringProperty.java
new file mode 100644
index 000000000..d95651fe3
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStringProperty.java
@@ -0,0 +1,62 @@
+/*
+ * 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.state;
+
+public class GLStringProperty extends GLAbstractAtomicProperty {
+ private final String mDefaultValue;
+ private String mCurrentValue;
+
+ public GLStringProperty(GLStateType type, String defaultValue) {
+ super(type);
+
+ mDefaultValue = mCurrentValue = defaultValue;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return mDefaultValue.equalsIgnoreCase(mCurrentValue);
+ }
+
+ @Override
+ public void setValue(Object value) {
+ if (value instanceof String) {
+ mCurrentValue = (String) value;
+ } else {
+ throw new IllegalArgumentException("Attempt to set non-string value for " //$NON-NLS-1$
+ + getType());
+ }
+ }
+
+ public void setValue(String value) {
+ mCurrentValue = value;
+ }
+
+ @Override
+ public Object getValue() {
+ return mCurrentValue;
+ }
+
+ @Override
+ public String getStringValue() {
+ return mCurrentValue;
+ }
+
+ @Override
+ public String toString() {
+ return getType() + "=" + getStringValue(); //$NON-NLS-1$
+ };
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/IGLProperty.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/IGLProperty.java
new file mode 100644
index 000000000..ed87fd231
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/IGLProperty.java
@@ -0,0 +1,63 @@
+/*
+ * 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.state;
+
+
+/**
+ * The GL state is modeled as a hierarchical set of properties, all of which implement
+ * this interface.
+ */
+public interface IGLProperty extends Cloneable {
+ /** Obtain the type of the property. */
+ GLStateType getType();
+
+ /** Is this a composite property?
+ * @return true if it is a list or structure of properties,
+ * false if it is a leaf level atomic property
+ * */
+ boolean isComposite();
+
+ /**
+ * Is the currently set value the default?
+ * @return true if current value matches the default (initial) value
+ */
+ boolean isDefault();
+
+ /** Set the current value for this property. */
+ void setValue(Object value);
+
+ /** Get the current value for this property. */
+ Object getValue();
+
+ /** Get the string representation for this property. */
+ String getStringValue();
+
+ /**
+ * Get the parent property that holds this property.
+ * @return null if this property is at the top level, parent otherwise
+ */
+ IGLProperty getParent();
+
+ /** Set the parent property that holds this property. */
+ void setParent(IGLProperty parent);
+
+ /** Deep clone this property. */
+ IGLProperty clone();
+
+ /** Pretty print current property value to the given writer. */
+ void prettyPrint(StatePrettyPrinter pp);
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/StatePrettyPrinter.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/StatePrettyPrinter.java
new file mode 100644
index 000000000..0ad9aa4d7
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/StatePrettyPrinter.java
@@ -0,0 +1,67 @@
+/*
+ * 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.state;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.utils.SdkUtils;
+
+public class StatePrettyPrinter {
+ private static final int SPACES_PER_INDENT = 4;
+ private final String mLineSeparator = SdkUtils.getLineSeparator();
+
+ private StringBuilder mSb = new StringBuilder(1000);
+ private int mIndentLevel = 0;
+
+ public void prettyPrint(@NonNull GLStateType name, @Nullable String value) {
+ indentLine(mIndentLevel * SPACES_PER_INDENT);
+
+ mSb.append(name.toString());
+
+ if (value != null) {
+ mSb.append(':');
+ mSb.append(value);
+ }
+ mSb.append(mLineSeparator);
+ }
+
+ public void prettyPrint(@NonNull String s) {
+ indentLine(mIndentLevel * SPACES_PER_INDENT);
+
+ mSb.append(s);
+ mSb.append(mLineSeparator);
+ }
+
+ private void indentLine(int spaces) {
+ for (int i = 0; i < spaces; i++) {
+ mSb.append(' ');
+ }
+ }
+
+ public void incrementIndentLevel() {
+ mIndentLevel++;
+ }
+
+ public void decrementIndentLevel() {
+ mIndentLevel--;
+ }
+
+ @Override
+ public String toString() {
+ return mSb.toString();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/BufferSubDataTransform.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/BufferSubDataTransform.java
new file mode 100644
index 000000000..393f1b9b7
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/BufferSubDataTransform.java
@@ -0,0 +1,76 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A {@link BufferSubDataTransform} updates a portion of the buffer data as specified by
+ * the {@link Function#glBufferSubData} function.
+ */
+public class BufferSubDataTransform implements IStateTransform {
+ private final IGLPropertyAccessor mAccessor;
+ private final int mOffset;
+
+ private final byte[] mSubData;
+ private byte[] mOldData;
+ private byte[] mNewData;
+
+ public BufferSubDataTransform(IGLPropertyAccessor accessor, int offset, byte[] data) {
+ mAccessor = accessor;
+ mOffset = offset;
+ mSubData = data;
+ }
+
+ @Override
+ public void apply(IGLProperty state) {
+ IGLProperty property = mAccessor.getProperty(state);
+ mOldData = (byte[]) property.getValue();
+
+ if (mOldData != null) {
+ mNewData = new byte[mOldData.length];
+ ByteBuffer bb = ByteBuffer.wrap(mNewData);
+
+ // copy all of the old buffer
+ bb.put(mOldData);
+ bb.rewind();
+
+ // update with the sub buffer data at specified offset
+ bb.position(mOffset);
+ bb.put(mSubData);
+ }
+
+ property.setValue(mNewData);
+ }
+
+ @Override
+ public void revert(IGLProperty state) {
+ if (mOldData != null) {
+ IGLProperty property = mAccessor.getProperty(state);
+ property.setValue(mOldData);
+ mOldData = null;
+ }
+ }
+
+ @Override
+ public IGLProperty getChangedProperty(IGLProperty state) {
+ return mAccessor.getProperty(state);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentProgramPropertyAccessor.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentProgramPropertyAccessor.java
new file mode 100644
index 000000000..9cc3cb885
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentProgramPropertyAccessor.java
@@ -0,0 +1,67 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.GLIntegerProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+public class CurrentProgramPropertyAccessor implements IGLPropertyAccessor {
+ private final int mContextId;
+ private final GLStateType mStateCategory;
+ private final int mLocation;
+ private final GLStateType mStateType;
+ private final IGLPropertyAccessor mCurrentProgramAccessor;
+
+ public CurrentProgramPropertyAccessor(int contextid, GLStateType stateCategory,
+ int location, GLStateType stateType) {
+ mContextId = contextid;
+ mStateCategory = stateCategory;
+ mLocation = location;
+ mStateType = stateType;
+
+ mCurrentProgramAccessor = GLPropertyAccessor.makeAccessor(contextid,
+ GLStateType.PROGRAM_STATE,
+ GLStateType.CURRENT_PROGRAM);
+ }
+
+ @Override
+ public IGLProperty getProperty(IGLProperty state) {
+ // obtain the current program
+ IGLProperty currentProgramProperty = mCurrentProgramAccessor.getProperty(state);
+ if (!(currentProgramProperty instanceof GLIntegerProperty)) {
+ return null;
+ }
+
+ Integer program = (Integer) currentProgramProperty.getValue();
+
+ // now access the required program property
+ return GLPropertyAccessor.makeAccessor(mContextId,
+ GLStateType.PROGRAM_STATE,
+ GLStateType.PROGRAMS,
+ program,
+ mStateCategory,
+ Integer.valueOf(mLocation),
+ mStateType).getProperty(state);
+ }
+
+ @Override
+ public String getPath() {
+ return String.format("PROGRAM_STATE/PROGRAMS/${program}/%s/%d/%s",
+ mStateCategory, mLocation, mStateType);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentVboPropertyAccessor.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentVboPropertyAccessor.java
new file mode 100644
index 000000000..bd1286d5b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentVboPropertyAccessor.java
@@ -0,0 +1,71 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.GLEnum;
+import com.android.ide.eclipse.gltrace.state.GLIntegerProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * An {@link IGLPropertyAccessor} that retrieves the requested property in the
+ * currently bound {@link GLEnum#GL_ARRAY_BUFFER} or {@link GLEnum#GL_ELEMENT_ARRAY_BUFFER}.
+ */
+public class CurrentVboPropertyAccessor implements IGLPropertyAccessor {
+ private final int mContextId;
+ private final IGLPropertyAccessor mVboBindingAccessor;
+ private final GLStateType mVboProperty;
+
+ public CurrentVboPropertyAccessor(int contextId, GLEnum target, GLStateType vboProperty) {
+ mContextId = contextId;
+ mVboProperty = vboProperty;
+
+ GLStateType vboType;
+ if (target == GLEnum.GL_ARRAY_BUFFER) {
+ vboType = GLStateType.ARRAY_BUFFER_BINDING;
+ } else {
+ vboType = GLStateType.ELEMENT_ARRAY_BUFFER_BINDING;
+ }
+
+ mVboBindingAccessor = GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.BUFFER_BINDINGS,
+ vboType);
+ }
+
+ @Override
+ public IGLProperty getProperty(IGLProperty state) {
+ // obtain the current bound buffer
+ IGLProperty currentBinding = mVboBindingAccessor.getProperty(state);
+ if (!(currentBinding instanceof GLIntegerProperty)) {
+ return null;
+ }
+
+ Integer buffer = (Integer) currentBinding.getValue();
+
+ return GLPropertyAccessor.makeAccessor(mContextId,
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VBO,
+ buffer,
+ mVboProperty).getProperty(state);
+ }
+
+ @Override
+ public String getPath() {
+ return String.format("VERTEX_ARRAY_DATA/VBO/${currentBuffer}/%s", mVboProperty);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/GLPropertyAccessor.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/GLPropertyAccessor.java
new file mode 100644
index 000000000..be338be19
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/GLPropertyAccessor.java
@@ -0,0 +1,139 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.GLCompositeProperty;
+import com.android.ide.eclipse.gltrace.state.GLListProperty;
+import com.android.ide.eclipse.gltrace.state.GLSparseArrayProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * GLPropertyAccessor's can be used to extract a certain property from the provided
+ * OpenGL State hierarchy.
+ */
+public class GLPropertyAccessor implements IGLPropertyAccessor {
+ private final int mContextId;
+ private final List<GLPropertyExtractor> mExtractors;
+
+ private GLPropertyAccessor(int contextId, List<GLPropertyExtractor> extractors) {
+ mContextId = contextId;
+ mExtractors = extractors;
+ }
+
+ @Override
+ public IGLProperty getProperty(IGLProperty state) {
+ IGLProperty root = ((GLListProperty) state).get(mContextId);
+
+ for (GLPropertyExtractor e : mExtractors) {
+ IGLProperty successor = e.getProperty(root);
+ if (successor == null) {
+ root = null;
+ break;
+ }
+ root = successor;
+ }
+
+ return root;
+ }
+
+ /**
+ * Factory method used to construct a {@link GLPropertyAccessor}.
+ * @param contextId id of affected context
+ * @param accessors list of accessor's to be used to navigate the property hierarchy. The
+ * accessors are either Integers or {@link GLStateType} objects. Integers
+ * are assumed to be indexes in a {@link GLListProperty} or
+ * {@link GLSparseArrayProperty}, and the GLStateType enum objects are
+ * used to query {@link GLCompositeProperty}'s.
+ */
+ public static IGLPropertyAccessor makeAccessor(int contextId, Object...accessors) {
+ List<GLPropertyExtractor> extractors = new ArrayList<GLPropertyExtractor>();
+
+ for (Object accessor : accessors) {
+ if (accessor instanceof GLStateType) {
+ extractors.add(new GLNamePropertyExtractor((GLStateType) accessor));
+ } else if (accessor instanceof Integer) {
+ extractors.add(new GLIndexPropertyExtractor((Integer) accessor));
+ } else {
+ throw new IllegalArgumentException("Unknown property (" + accessor
+ + ") used to access members of IGLProperty");
+ }
+ }
+
+ return new GLPropertyAccessor(contextId, extractors);
+ }
+
+ private interface GLPropertyExtractor {
+ IGLProperty getProperty(IGLProperty p);
+ }
+
+ /** Extract properties by name. */
+ private static class GLNamePropertyExtractor implements GLPropertyExtractor {
+ private final GLStateType mType;
+
+ public GLNamePropertyExtractor(GLStateType type) {
+ mType = type;
+ }
+
+ @Override
+ public IGLProperty getProperty(IGLProperty p) {
+ if (p instanceof GLCompositeProperty) {
+ return ((GLCompositeProperty) p).getProperty(mType);
+ }
+
+ return null;
+ }
+ }
+
+ /** Extract properties by index. */
+ private static class GLIndexPropertyExtractor implements GLPropertyExtractor {
+ private final int mIndex;
+
+ public GLIndexPropertyExtractor(int index) {
+ mIndex = index;
+ }
+
+ @Override
+ public IGLProperty getProperty(IGLProperty p) {
+ if (p instanceof GLListProperty && mIndex >= 0) {
+ return ((GLListProperty) p).get(mIndex);
+ }
+ if (p instanceof GLSparseArrayProperty) {
+ return ((GLSparseArrayProperty) p).getProperty(mIndex);
+ }
+ return null;
+ }
+ }
+
+ @Override
+ public String getPath() {
+ StringBuilder sb = new StringBuilder(mExtractors.size() * 10);
+ for (GLPropertyExtractor e: mExtractors) {
+ if (e instanceof GLNamePropertyExtractor) {
+ sb.append(((GLNamePropertyExtractor) e).mType);
+ } else {
+ sb.append(((GLIndexPropertyExtractor) e).mIndex);
+ }
+ sb.append('/');
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IGLPropertyAccessor.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IGLPropertyAccessor.java
new file mode 100644
index 000000000..5df21b950
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IGLPropertyAccessor.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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * An {@link IGLPropertyAccessor} provides an interface to extract
+ * a specific property from a composite property.
+ */
+public interface IGLPropertyAccessor {
+ /** Obtain a specific property from the given state. */
+ IGLProperty getProperty(IGLProperty state);
+
+ /** Returns the string representation of this property accessor. */
+ String getPath();
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IPredicate.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IPredicate.java
new file mode 100644
index 000000000..e31226ffb
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IPredicate.java
@@ -0,0 +1,21 @@
+/*
+ * 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.state.transforms;
+
+public interface IPredicate {
+ boolean apply(Object value);
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IStateTransform.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IStateTransform.java
new file mode 100644
index 000000000..de33a08f0
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IStateTransform.java
@@ -0,0 +1,34 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * This interface encapsulates a single change to the GL state. GL Calls that affect
+ * multiple state variables would use a list of these state transformations.
+ */
+public interface IStateTransform {
+ /** Apply this transformation on the given state. */
+ void apply(IGLProperty currentState);
+
+ /** Revert this transformation from the given state. */
+ void revert(IGLProperty currentState);
+
+ /** Obtain the property that will be affected by this transformation. */
+ IGLProperty getChangedProperty(IGLProperty currentState);
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/ListElementAddTransform.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/ListElementAddTransform.java
new file mode 100644
index 000000000..dcf50d7e8
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/ListElementAddTransform.java
@@ -0,0 +1,69 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.GLListProperty;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * A {@link ListElementAddTransform} provides the ability to add a new property to a list of
+ * properties in the GL State.
+ */
+public class ListElementAddTransform implements IStateTransform {
+ private final IGLPropertyAccessor mAccessor;
+ private final IGLProperty mElement;
+
+ public ListElementAddTransform(IGLPropertyAccessor accessor, IGLProperty element) {
+ mAccessor = accessor;
+ mElement = element;
+ }
+
+ @Override
+ public void apply(IGLProperty currentState) {
+ GLListProperty list = getList(currentState);
+ if (list != null) {
+ list.add(mElement);
+ }
+ }
+
+ @Override
+ public void revert(IGLProperty currentState) {
+ GLListProperty list = getList(currentState);
+ if (list != null) {
+ list.remove(mElement);
+ }
+ }
+
+ @Override
+ public IGLProperty getChangedProperty(IGLProperty currentState) {
+ return getList(currentState);
+ }
+
+ private GLListProperty getList(IGLProperty state) {
+ IGLProperty p = state;
+
+ if (mAccessor != null) {
+ p = mAccessor.getProperty(p);
+ }
+
+ if (p instanceof GLListProperty) {
+ return (GLListProperty) p;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/Predicates.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/Predicates.java
new file mode 100644
index 000000000..0de8358c8
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/Predicates.java
@@ -0,0 +1,36 @@
+/*
+ * 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.state.transforms;
+
+public class Predicates {
+ private static class IntegerPropertyEqualsPredicate implements IPredicate {
+ private int mExpected;
+
+ public IntegerPropertyEqualsPredicate(Integer expected) {
+ mExpected = expected.intValue();
+ }
+
+ @Override
+ public boolean apply(Object value) {
+ return value instanceof Integer && ((Integer) value).intValue() == mExpected;
+ }
+ }
+
+ public static IPredicate matchesInteger(int expected) {
+ return new IntegerPropertyEqualsPredicate(expected);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/PropertyChangeTransform.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/PropertyChangeTransform.java
new file mode 100644
index 000000000..276f6f49b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/PropertyChangeTransform.java
@@ -0,0 +1,103 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * A PropertyChangeTransform object provides the ability to alter the value of a
+ * single GL State variable. An optional predicate provides the ability to perform
+ * the change only if the predicate succeeds.
+ */
+public class PropertyChangeTransform implements IStateTransform {
+ private final IGLPropertyAccessor mAccessor;
+ private final Object mNewValue;
+ private final IPredicate mPredicate;
+ private Object mOldValue;
+
+ /**
+ * Construct a state transform that will extract the property using the accessor,
+ * and modify its value to the provided value.
+ */
+ PropertyChangeTransform(IGLPropertyAccessor accessor, Object newValue) {
+ this(accessor, newValue, null);
+ }
+
+ /**
+ * Construct a state transform that will extract the property using the accessor,
+ * check if the predicate function accepts the current value, and if so modify its
+ * value to the provided value.
+ */
+ public PropertyChangeTransform(IGLPropertyAccessor accessor, Object newValue,
+ IPredicate predicate) {
+ mAccessor = accessor;
+ mNewValue = newValue;
+ mPredicate = predicate;
+ mOldValue = null;
+ }
+
+ /** Apply the state transformation on the given OpenGL state. */
+ @Override
+ public void apply(IGLProperty state) {
+ IGLProperty property = mAccessor.getProperty(state);
+
+ assert mOldValue == null : "Transform cannot be applied multiple times";
+ if (mPredicate != null) {
+ // if predicate is not null, then first check if the current value
+ // passes the predicate function.
+ if (!mPredicate.apply(property.getValue())) {
+ return;
+ }
+ }
+
+ if (property != null) {
+ mOldValue = property.getValue();
+ property.setValue(mNewValue);
+ } else {
+ throw new RuntimeException("No such property: " + mAccessor.getPath());
+ }
+ }
+
+ /**
+ * Reverses the effect of this state transform. It restores the property's value to the same
+ * state as it was before this transformation was applied. If this transform was never
+ * {@link #apply(IGLProperty)}'ed, then performing a revert has no effect.
+ */
+ @Override
+ public void revert(IGLProperty state) {
+ if (mOldValue != null) {
+ IGLProperty property = mAccessor.getProperty(state);
+ property.setValue(mOldValue);
+ mOldValue = null;
+ }
+ }
+
+ /** Gets the property that will be affected by applying this transformation. */
+ @Override
+ public IGLProperty getChangedProperty(IGLProperty state) {
+ if (mPredicate != null) {
+ Object value = mOldValue == null ? mNewValue : mOldValue;
+ if (!mPredicate.apply(value)) {
+ // if the value doesn't match the predicate, then this property
+ // is not altered.
+ return null;
+ }
+ }
+
+ return mAccessor.getProperty(state);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementAddTransform.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementAddTransform.java
new file mode 100644
index 000000000..b7547bc9a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementAddTransform.java
@@ -0,0 +1,77 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.GLSparseArrayProperty;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * A {@link SparseArrayElementAddTransform} changes given state by adding an
+ * element to a sparse array, if there is no item with the same key already.
+ */
+public class SparseArrayElementAddTransform implements IStateTransform {
+ private IGLPropertyAccessor mAccessor;
+ private int mKey;
+ private IGLProperty mOldValue;
+
+ public SparseArrayElementAddTransform(IGLPropertyAccessor accessor, int key) {
+ mAccessor = accessor;
+ mKey = key;
+ }
+
+ @Override
+ public void apply(IGLProperty currentState) {
+ GLSparseArrayProperty propertyArray = getArray(currentState);
+ if (propertyArray != null) {
+ mOldValue = propertyArray.getProperty(mKey);
+ if (mOldValue == null) {
+ // add only if there is no item with this key already present
+ propertyArray.add(mKey);
+ }
+ }
+ }
+
+ @Override
+ public void revert(IGLProperty currentState) {
+ GLSparseArrayProperty propertyArray = getArray(currentState);
+ if (propertyArray != null) {
+ if (mOldValue == null) {
+ // delete only if we actually added this key
+ propertyArray.delete(mKey);
+ }
+ }
+ }
+
+ @Override
+ public IGLProperty getChangedProperty(IGLProperty currentState) {
+ return getArray(currentState);
+ }
+
+ private GLSparseArrayProperty getArray(IGLProperty state) {
+ IGLProperty p = state;
+
+ if (mAccessor != null) {
+ p = mAccessor.getProperty(p);
+ }
+
+ if (p instanceof GLSparseArrayProperty) {
+ return (GLSparseArrayProperty) p;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementRemoveTransform.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementRemoveTransform.java
new file mode 100644
index 000000000..c1ff211bd
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementRemoveTransform.java
@@ -0,0 +1,49 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * A {@link SparseArrayElementRemoveTransform} changes given state by removing an
+ * element from a sparse array.
+ */
+public class SparseArrayElementRemoveTransform implements IStateTransform {
+ private final SparseArrayElementAddTransform mAddTransform;
+
+ public SparseArrayElementRemoveTransform(IGLPropertyAccessor accessor, int key) {
+ mAddTransform = new SparseArrayElementAddTransform(accessor, key);
+ }
+
+ @Override
+ public void apply(IGLProperty currentState) {
+ // applying a RemoveTransform is the same as reverting an AddTransform.
+ mAddTransform.revert(currentState);
+ }
+
+ @Override
+ public void revert(IGLProperty currentState) {
+ // reverting a RemoveTransform is the same as applying an AddTransform.
+ mAddTransform.apply(currentState);
+ }
+
+ @Override
+ public IGLProperty getChangedProperty(IGLProperty currentState) {
+ return mAddTransform.getChangedProperty(currentState);
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java
new file mode 100644
index 000000000..023f84b6a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java
@@ -0,0 +1,1384 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.FileUtils;
+import com.android.ide.eclipse.gltrace.GLEnum;
+import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage;
+import com.android.ide.eclipse.gltrace.state.GLState;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+import com.google.common.io.Files;
+import com.google.protobuf.ByteString;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+public class StateTransformFactory {
+ private static final String TEXTURE_DATA_FILE_PREFIX = "tex"; //$NON-NLS-1$
+ private static final String TEXTURE_DATA_FILE_SUFFIX = ".dat"; //$NON-NLS-1$
+ private static EnumSet<GLEnum> sTexParameterPnameValues;
+
+ /** Construct a list of transformations to be applied for the provided OpenGL call. */
+ public static List<IStateTransform> getTransformsFor(GLMessage msg) {
+ switch (msg.getFunction()) {
+ case eglCreateContext:
+ return transformsForEglCreateContext(msg);
+ case glBindFramebuffer:
+ return transformsForGlBindFramebuffer(msg);
+
+ // vertex data
+ case glVertexAttribPointer:
+ return transformsForGlVertexAttribPointer(msg);
+ case glVertexAttrib1f:
+ case glVertexAttrib2f:
+ case glVertexAttrib3f:
+ case glVertexAttrib4f:
+ return transformsForGlVertexAttribxf(msg);
+ case glVertexAttrib1fv:
+ case glVertexAttrib2fv:
+ case glVertexAttrib3fv:
+ case glVertexAttrib4fv:
+ return transformsForGlVertexAttribxfv(msg);
+ case glEnableVertexAttribArray:
+ return transformsForGlEnableVertexAttribArray(msg);
+ case glDisableVertexAttribArray:
+ return transformsForGlDisableVertexAttribArray(msg);
+
+ // VBO's
+ case glBindBuffer:
+ return transformsForGlBindBuffer(msg);
+ case glGenBuffers:
+ return transformsForGlGenBuffers(msg);
+ case glDeleteBuffers:
+ return transformsForGlDeleteBuffers(msg);
+ case glBufferData:
+ return transformsForGlBufferData(msg);
+ case glBufferSubData:
+ return transformsForGlBufferSubData(msg);
+
+ // transformation state
+ case glViewport:
+ return transformsForGlViewport(msg);
+ case glDepthRangef:
+ return transformsForGlDepthRangef(msg);
+
+ // rasterization
+ case glLineWidth:
+ return transformsForGlLineWidth(msg);
+ case glCullFace:
+ return transformsForGlCullFace(msg);
+ case glFrontFace:
+ return transformsForGlFrontFace(msg);
+ case glPolygonOffset:
+ return transformsForGlPolygonOffset(msg);
+
+ // pixel operations
+ case glScissor:
+ return transformsForGlScissor(msg);
+ case glStencilFunc:
+ return transformsForGlStencilFunc(msg);
+ case glStencilFuncSeparate:
+ return transformsForGlStencilFuncSeparate(msg);
+ case glStencilOp:
+ return transformsForGlStencilOp(msg);
+ case glStencilOpSeparate:
+ return transformsForGlStencilOpSeparate(msg);
+ case glDepthFunc:
+ return transformsForGlDepthFunc(msg);
+ case glBlendEquation:
+ return transformsForGlBlendEquation(msg);
+ case glBlendEquationSeparate:
+ return transformsForGlBlendEquationSeparate(msg);
+ case glBlendFunc:
+ return transformsForGlBlendFunc(msg);
+ case glBlendFuncSeparate:
+ return transformsForGlBlendFuncSeparate(msg);
+ case glPixelStorei:
+ return transformsForGlPixelStorei(msg);
+
+ // Texture State Transformations
+ case glGenTextures:
+ return transformsForGlGenTextures(msg);
+ case glDeleteTextures:
+ return transformsForGlDeleteTextures(msg);
+ case glActiveTexture:
+ return transformsForGlActiveTexture(msg);
+ case glBindTexture:
+ return transformsForGlBindTexture(msg);
+ case glTexImage2D:
+ return transformsForGlTexImage2D(msg);
+ case glTexSubImage2D:
+ return transformsForGlTexSubImage2D(msg);
+ case glTexParameteri:
+ return transformsForGlTexParameter(msg);
+
+ // Program State Transformations
+ case glCreateProgram:
+ return transformsForGlCreateProgram(msg);
+ case glUseProgram:
+ return transformsForGlUseProgram(msg);
+ case glAttachShader:
+ return transformsForGlAttachShader(msg);
+ case glDetachShader:
+ return transformsForGlDetachShader(msg);
+ case glGetActiveAttrib:
+ return transformsForGlGetActiveAttrib(msg);
+ case glGetActiveUniform:
+ return transformsForGlGetActiveUniform(msg);
+ case glUniform1i:
+ case glUniform2i:
+ case glUniform3i:
+ case glUniform4i:
+ return transformsForGlUniform(msg, false);
+ case glUniform1f:
+ case glUniform2f:
+ case glUniform3f:
+ case glUniform4f:
+ return transformsForGlUniform(msg, true);
+ case glUniform1iv:
+ case glUniform2iv:
+ case glUniform3iv:
+ case glUniform4iv:
+ return transformsForGlUniformv(msg, false);
+ case glUniform1fv:
+ case glUniform2fv:
+ case glUniform3fv:
+ case glUniform4fv:
+ return transformsForGlUniformv(msg, true);
+ case glUniformMatrix2fv:
+ case glUniformMatrix3fv:
+ case glUniformMatrix4fv:
+ return transformsForGlUniformMatrix(msg);
+
+ // Shader State Transformations
+ case glCreateShader:
+ return transformsForGlCreateShader(msg);
+ case glDeleteShader:
+ return transformsForGlDeleteShader(msg);
+ case glShaderSource:
+ return transformsForGlShaderSource(msg);
+ default:
+ return Collections.emptyList();
+ }
+ }
+
+ private static List<IStateTransform> transformsForGlVertexAttribPointer(GLMessage msg) {
+ int index = msg.getArgs(0).getIntValue(0);
+
+ int size = msg.getArgs(1).getIntValue(0);
+ int type = msg.getArgs(2).getIntValue(0);
+ boolean normalized = msg.getArgs(3).getBoolValue(0);
+ int stride = msg.getArgs(4).getIntValue(0);
+
+ long pointer;
+ if (msg.getArgs(5).getIntValueCount() > 0) {
+ pointer = msg.getArgs(5).getIntValue(0);
+ } else {
+ pointer = msg.getArgs(5).getInt64Value(0);
+ }
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VERTEX_ATTRIB_ARRAY,
+ Integer.valueOf(index),
+ GLStateType.VERTEX_ATTRIB_ARRAY_SIZE),
+ Integer.valueOf(size)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VERTEX_ATTRIB_ARRAY,
+ Integer.valueOf(index),
+ GLStateType.VERTEX_ATTRIB_ARRAY_TYPE),
+ GLEnum.valueOf(type)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VERTEX_ATTRIB_ARRAY,
+ Integer.valueOf(index),
+ GLStateType.VERTEX_ATTRIB_ARRAY_NORMALIZED),
+ Boolean.valueOf(normalized)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VERTEX_ATTRIB_ARRAY,
+ Integer.valueOf(index),
+ GLStateType.VERTEX_ATTRIB_ARRAY_STRIDE),
+ Integer.valueOf(stride)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VERTEX_ATTRIB_ARRAY,
+ Integer.valueOf(index),
+ GLStateType.VERTEX_ATTRIB_ARRAY_POINTER),
+ Long.valueOf(pointer)));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlVertexAttrib(int context,
+ int index, float v0, float v1, float v2, float v3) {
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>(4);
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(context,
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.GENERIC_VERTEX_ATTRIBUTES,
+ Integer.valueOf(index),
+ GLStateType.GENERIC_VERTEX_ATTRIB_V0),
+ Float.valueOf(v0)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(context,
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.GENERIC_VERTEX_ATTRIBUTES,
+ Integer.valueOf(index),
+ GLStateType.GENERIC_VERTEX_ATTRIB_V1),
+ Float.valueOf(v1)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(context,
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.GENERIC_VERTEX_ATTRIBUTES,
+ Integer.valueOf(index),
+ GLStateType.GENERIC_VERTEX_ATTRIB_V2),
+ Float.valueOf(v2)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(context,
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.GENERIC_VERTEX_ATTRIBUTES,
+ Integer.valueOf(index),
+ GLStateType.GENERIC_VERTEX_ATTRIB_V3),
+ Float.valueOf(v3)));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlVertexAttribxf(GLMessage msg) {
+ // void glVertexAttrib1f(GLuint index, GLfloat v0);
+ // void glVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1);
+ // void glVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2);
+ // void glVertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+
+ int index = msg.getArgs(0).getIntValue(0);
+ float v0 = msg.getArgs(1).getFloatValue(0);
+ float v1 = msg.getArgsCount() > 2 ? msg.getArgs(2).getFloatValue(0) : 0;
+ float v2 = msg.getArgsCount() > 3 ? msg.getArgs(3).getFloatValue(0) : 0;
+ float v3 = msg.getArgsCount() > 4 ? msg.getArgs(4).getFloatValue(0) : 0;
+
+ return transformsForGlVertexAttrib(msg.getContextId(), index, v0, v1, v2, v3);
+ }
+
+ private static List<IStateTransform> transformsForGlVertexAttribxfv(GLMessage msg) {
+ // void glVertexAttrib1fv(GLuint index, const GLfloat *v);
+ // void glVertexAttrib2fv(GLuint index, const GLfloat *v);
+ // void glVertexAttrib3fv(GLuint index, const GLfloat *v);
+ // void glVertexAttrib4fv(GLuint index, const GLfloat *v);
+
+ int index = msg.getArgs(0).getIntValue(0);
+ float v[] = new float[4];
+
+ for (int i = 0; i < msg.getArgs(1).getFloatValueList().size(); i++) {
+ v[i] = msg.getArgs(1).getFloatValue(i);
+ }
+
+ return transformsForGlVertexAttrib(msg.getContextId(), index, v[0], v[1], v[2], v[3]);
+ }
+
+ private static List<IStateTransform> transformsForGlEnableVertexAttribArray(GLMessage msg) {
+ // void glEnableVertexAttribArray(GLuint index);
+ // void glDisableVertexAttribArray(GLuint index);
+
+ int index = msg.getArgs(0).getIntValue(0);
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VERTEX_ATTRIB_ARRAY,
+ Integer.valueOf(index),
+ GLStateType.VERTEX_ATTRIB_ARRAY_ENABLED),
+ Boolean.TRUE);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlDisableVertexAttribArray(GLMessage msg) {
+ // void glEnableVertexAttribArray(GLuint index);
+ // void glDisableVertexAttribArray(GLuint index);
+
+ int index = msg.getArgs(0).getIntValue(0);
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VERTEX_ATTRIB_ARRAY,
+ Integer.valueOf(index),
+ GLStateType.VERTEX_ATTRIB_ARRAY_ENABLED),
+ Boolean.FALSE);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlBindBuffer(GLMessage msg) {
+ // void glBindBuffer(GLenum target, GLuint buffer);
+ // target is one of GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER.
+
+ GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ int buffer = msg.getArgs(1).getIntValue(0);
+ GLStateType bufferType;
+
+ if (target == GLEnum.GL_ARRAY_BUFFER) {
+ bufferType = GLStateType.ARRAY_BUFFER_BINDING;
+ } else {
+ bufferType = GLStateType.ELEMENT_ARRAY_BUFFER_BINDING;
+ }
+
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.BUFFER_BINDINGS,
+ bufferType),
+ Integer.valueOf(buffer));
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlGenBuffers(GLMessage msg) {
+ // void glGenBuffers(GLsizei n, GLuint * buffers);
+ int n = msg.getArgs(0).getIntValue(0);
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+
+ for (int i = 0; i < n; i++) {
+ transforms.add(new SparseArrayElementAddTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VBO),
+ msg.getArgs(1).getIntValue(i)));
+ }
+
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlDeleteBuffers(GLMessage msg) {
+ // void glDeleteBuffers(GLsizei n, const GLuint * buffers);
+ int n = msg.getArgs(0).getIntValue(0);
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+
+ for (int i = 0; i < n; i++) {
+ transforms.add(new SparseArrayElementRemoveTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.VERTEX_ARRAY_DATA,
+ GLStateType.VBO),
+ msg.getArgs(1).getIntValue(i)));
+ }
+
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlBufferData(GLMessage msg) {
+ // void glBufferData(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage);
+ GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ int size = msg.getArgs(1).getIntValue(0);
+ byte[] data = null;
+ GLEnum usage = GLEnum.valueOf(msg.getArgs(3).getIntValue(0));
+
+ if (msg.getArgs(2).getRawBytesList().size() > 0) {
+ data = msg.getArgs(2).getRawBytesList().get(0).toByteArray();
+ } else {
+ data = new byte[size];
+ }
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+
+ transforms.add(new PropertyChangeTransform(
+ new CurrentVboPropertyAccessor(msg.getContextId(),
+ target,
+ GLStateType.BUFFER_SIZE),
+ Integer.valueOf(size)));
+ transforms.add(new PropertyChangeTransform(
+ new CurrentVboPropertyAccessor(msg.getContextId(),
+ target,
+ GLStateType.BUFFER_DATA),
+ data));
+ transforms.add(new PropertyChangeTransform(
+ new CurrentVboPropertyAccessor(msg.getContextId(),
+ target,
+ GLStateType.BUFFER_USAGE),
+ usage));
+ transforms.add(new PropertyChangeTransform(
+ new CurrentVboPropertyAccessor(msg.getContextId(),
+ target,
+ GLStateType.BUFFER_TYPE),
+ target));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlBufferSubData(GLMessage msg) {
+ // void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);
+ GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ int offset = msg.getArgs(1).getIntValue(0);
+ byte[] data = msg.getArgs(3).getRawBytesList().get(0).toByteArray();
+
+ IStateTransform transform = new BufferSubDataTransform(
+ new CurrentVboPropertyAccessor(msg.getContextId(),
+ target,
+ GLStateType.BUFFER_DATA),
+ offset, data);
+
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlBindFramebuffer(GLMessage msg) {
+ // void glBindFramebuffer(GLenum target, GLuint framebuffer);
+ int fb = msg.getArgs(1).getIntValue(0);
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.FRAMEBUFFER_STATE,
+ GLStateType.FRAMEBUFFER_BINDING),
+ fb);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlLineWidth(GLMessage msg) {
+ // void glLineWidth(GLfloat width);
+ float width = msg.getArgs(0).getFloatValue(0);
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.RASTERIZATION_STATE,
+ GLStateType.LINE_WIDTH),
+ width);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlCullFace(GLMessage msg) {
+ // void glCullFace(GLenum mode);
+ int mode = msg.getArgs(0).getIntValue(0);
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.RASTERIZATION_STATE,
+ GLStateType.CULL_FACE_MODE),
+ GLEnum.valueOf(mode));
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlFrontFace(GLMessage msg) {
+ // void glFrontFace(GLenum mode);
+ int mode = msg.getArgs(0).getIntValue(0);
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.RASTERIZATION_STATE,
+ GLStateType.FRONT_FACE),
+ GLEnum.valueOf(mode));
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlPolygonOffset(GLMessage msg) {
+ // void glPolygonOffset(GLfloat factor, GLfloat units)
+ float factor = msg.getArgs(0).getFloatValue(0);
+ float units = msg.getArgs(1).getFloatValue(0);
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.RASTERIZATION_STATE,
+ GLStateType.POLYGON_OFFSET_FACTOR),
+ Float.valueOf(factor)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.RASTERIZATION_STATE,
+ GLStateType.POLYGON_OFFSET_UNITS),
+ Float.valueOf(units)));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlScissor(GLMessage msg) {
+ // void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
+ int x = msg.getArgs(0).getIntValue(0);
+ int y = msg.getArgs(1).getIntValue(0);
+ int w = msg.getArgs(2).getIntValue(0);
+ int h = msg.getArgs(3).getIntValue(0);
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.SCISSOR_BOX,
+ GLStateType.SCISSOR_BOX_X),
+ Integer.valueOf(x)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.SCISSOR_BOX,
+ GLStateType.SCISSOR_BOX_Y),
+ Integer.valueOf(y)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.SCISSOR_BOX,
+ GLStateType.SCISSOR_BOX_WIDTH),
+ Integer.valueOf(w)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.SCISSOR_BOX,
+ GLStateType.SCISSOR_BOX_HEIGHT),
+ Integer.valueOf(h)));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlStencilFuncFront(int contextId,
+ GLEnum func, int ref, int mask) {
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_FUNC),
+ func));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_REF),
+ Integer.valueOf(ref)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_VALUE_MASK),
+ Integer.valueOf(mask)));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlStencilFuncBack(int contextId,
+ GLEnum func, int ref, int mask) {
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_BACK_FUNC),
+ func));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_BACK_REF),
+ Integer.valueOf(ref)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_BACK_VALUE_MASK),
+ Integer.valueOf(mask)));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlStencilFunc(GLMessage msg) {
+ // void glStencilFunc(GLenum func, GLint ref, GLuint mask);
+ GLEnum func = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ int ref = msg.getArgs(1).getIntValue(0);
+ int mask = msg.getArgs(2).getIntValue(0);
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.addAll(transformsForGlStencilFuncFront(msg.getContextId(), func, ref, mask));
+ transforms.addAll(transformsForGlStencilFuncBack(msg.getContextId(), func, ref, mask));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlStencilFuncSeparate(GLMessage msg) {
+ // void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
+ GLEnum face = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ GLEnum func = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
+ int ref = msg.getArgs(2).getIntValue(0);
+ int mask = msg.getArgs(3).getIntValue(0);
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ if (face == GLEnum.GL_FRONT || face == GLEnum.GL_FRONT_AND_BACK) {
+ transforms.addAll(
+ transformsForGlStencilFuncFront(msg.getContextId(), func, ref, mask));
+ }
+ if (face == GLEnum.GL_BACK || face == GLEnum.GL_FRONT_AND_BACK) {
+ transforms.addAll(
+ transformsForGlStencilFuncBack(msg.getContextId(), func, ref, mask));
+ }
+
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlStencilOpFront(int contextId,
+ GLEnum sfail, GLEnum dpfail, GLEnum dppass) {
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_FAIL),
+ sfail));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_PASS_DEPTH_FAIL),
+ dpfail));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_PASS_DEPTH_PASS),
+ dppass));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlStencilOpBack(int contextId,
+ GLEnum sfail, GLEnum dpfail, GLEnum dppass) {
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_BACK_FAIL),
+ sfail));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_BACK_PASS_DEPTH_FAIL),
+ dpfail));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.STENCIL,
+ GLStateType.STENCIL_BACK_PASS_DEPTH_PASS),
+ dppass));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlStencilOp(GLMessage msg) {
+ // void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
+ GLEnum sfail = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ GLEnum dpfail = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
+ GLEnum dppass = GLEnum.valueOf(msg.getArgs(2).getIntValue(0));
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.addAll(
+ transformsForGlStencilOpFront(msg.getContextId(), sfail, dpfail, dppass));
+ transforms.addAll(
+ transformsForGlStencilOpBack(msg.getContextId(), sfail, dpfail, dppass));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlStencilOpSeparate(GLMessage msg) {
+ // void glStencilOp(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+ GLEnum face = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ GLEnum sfail = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
+ GLEnum dpfail = GLEnum.valueOf(msg.getArgs(2).getIntValue(0));
+ GLEnum dppass = GLEnum.valueOf(msg.getArgs(3).getIntValue(0));
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+
+ if (face == GLEnum.GL_FRONT || face == GLEnum.GL_FRONT_AND_BACK) {
+ transforms.addAll(
+ transformsForGlStencilOpFront(msg.getContextId(), sfail, dpfail, dppass));
+ }
+
+ if (face == GLEnum.GL_BACK || face == GLEnum.GL_FRONT_AND_BACK) {
+ transforms.addAll(
+ transformsForGlStencilOpBack(msg.getContextId(), sfail, dpfail, dppass));
+ }
+
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlDepthFunc(GLMessage msg) {
+ // void glDepthFunc(GLenum func);
+ GLEnum func = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.DEPTH_FUNC),
+ func);
+ return Collections.singletonList(transform);
+ }
+
+ private static IStateTransform transformForGlEquationRGB(int contextId, GLEnum mode) {
+ return new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.BLEND,
+ GLStateType.BLEND_EQUATION_RGB),
+ mode);
+ }
+
+ private static IStateTransform transformForGlEquationAlpha(int contextId, GLEnum mode) {
+ return new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.BLEND,
+ GLStateType.BLEND_EQUATION_ALPHA),
+ mode);
+ }
+
+ private static List<IStateTransform> transformsForGlBlendEquationSeparate(GLMessage msg) {
+ // void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
+ GLEnum rgb = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ GLEnum alpha = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(transformForGlEquationRGB(msg.getContextId(), rgb));
+ transforms.add(transformForGlEquationAlpha(msg.getContextId(), alpha));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlBlendEquation(GLMessage msg) {
+ // void glBlendEquation(GLenum mode);
+ GLEnum mode = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(transformForGlEquationRGB(msg.getContextId(), mode));
+ transforms.add(transformForGlEquationAlpha(msg.getContextId(), mode));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlBlendFuncSrcDst(boolean src,
+ int contextId, GLEnum rgb, GLEnum alpha) {
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+
+ GLStateType rgbAccessor = GLStateType.BLEND_DST_RGB;
+ GLStateType alphaAccessor = GLStateType.BLEND_DST_ALPHA;
+ if (src) {
+ rgbAccessor = GLStateType.BLEND_SRC_RGB;
+ alphaAccessor = GLStateType.BLEND_SRC_ALPHA;
+ }
+
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.BLEND,
+ rgbAccessor),
+ rgb));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.PIXEL_OPERATIONS,
+ GLStateType.BLEND,
+ alphaAccessor),
+ alpha));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlBlendFuncSeparate(GLMessage msg) {
+ // void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+ GLEnum srcRgb = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ GLEnum dstRgb = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
+ GLEnum srcAlpha = GLEnum.valueOf(msg.getArgs(2).getIntValue(0));
+ GLEnum dstAlpha = GLEnum.valueOf(msg.getArgs(3).getIntValue(0));
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.addAll(transformsForGlBlendFuncSrcDst(true,
+ msg.getContextId(), srcRgb, srcAlpha));
+ transforms.addAll(transformsForGlBlendFuncSrcDst(false,
+ msg.getContextId(), dstRgb, dstAlpha));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlBlendFunc(GLMessage msg) {
+ // void glBlendFunc(GLenum sfactor, GLenum dfactor);
+ GLEnum sfactor = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ GLEnum dfactor = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.addAll(transformsForGlBlendFuncSrcDst(true,
+ msg.getContextId(), sfactor, sfactor));
+ transforms.addAll(transformsForGlBlendFuncSrcDst(false,
+ msg.getContextId(), dfactor, dfactor));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlPixelStorei(GLMessage msg) {
+ // void glPixelStorei(GLenum pname, GLint param);
+ GLEnum pname = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ Integer param = Integer.valueOf(msg.getArgs(1).getIntValue(0));
+
+ IStateTransform transform;
+ if (pname == GLEnum.GL_PACK_ALIGNMENT) {
+ transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PIXEL_PACKING,
+ GLStateType.PACK_ALIGNMENT),
+ param);
+ } else {
+ transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PIXEL_PACKING,
+ GLStateType.UNPACK_ALIGNMENT),
+ param);
+ }
+
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlViewport(GLMessage msg) {
+ // void glViewport( GLint x, GLint y, GLsizei width, GLsizei height);
+ int x = msg.getArgs(0).getIntValue(0);
+ int y = msg.getArgs(1).getIntValue(0);
+ int w = msg.getArgs(2).getIntValue(0);
+ int h = msg.getArgs(3).getIntValue(0);
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TRANSFORMATION_STATE,
+ GLStateType.VIEWPORT,
+ GLStateType.VIEWPORT_X),
+ Integer.valueOf(x)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TRANSFORMATION_STATE,
+ GLStateType.VIEWPORT,
+ GLStateType.VIEWPORT_Y),
+ Integer.valueOf(y)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TRANSFORMATION_STATE,
+ GLStateType.VIEWPORT,
+ GLStateType.VIEWPORT_WIDTH),
+ Integer.valueOf(w)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TRANSFORMATION_STATE,
+ GLStateType.VIEWPORT,
+ GLStateType.VIEWPORT_HEIGHT),
+ Integer.valueOf(h)));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlDepthRangef(GLMessage msg) {
+ // void glDepthRangef(GLclampf nearVal, GLclampf farVal);
+ float near = msg.getArgs(0).getFloatValue(0);
+ float far = msg.getArgs(1).getFloatValue(0);
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TRANSFORMATION_STATE,
+ GLStateType.DEPTH_RANGE,
+ GLStateType.DEPTH_RANGE_NEAR),
+ Float.valueOf(near)));
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TRANSFORMATION_STATE,
+ GLStateType.DEPTH_RANGE,
+ GLStateType.DEPTH_RANGE_FAR),
+ Float.valueOf(far)));
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlGenTextures(GLMessage msg) {
+ // void glGenTextures(GLsizei n, GLuint *textures);
+ int n = msg.getArgs(0).getIntValue(0);
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ for (int i = 0; i < n; i++) {
+ int texture = msg.getArgs(1).getIntValue(i);
+ transforms.add(new SparseArrayElementAddTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TEXTURE_STATE,
+ GLStateType.TEXTURES),
+ texture));
+ }
+
+ return transforms;
+ }
+
+ /**
+ * Obtain a list of transforms that will reset any existing texture units
+ * that are bound to provided texture.
+ * @param contextId context to operate on
+ * @param texture texture that should be unbound
+ */
+ private static List<IStateTransform> transformsToResetBoundTextureUnits(int contextId,
+ int texture) {
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>(
+ GLState.TEXTURE_UNIT_COUNT);
+
+ for (int i = 0; i < GLState.TEXTURE_UNIT_COUNT; i++) {
+ transforms.add(new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(contextId,
+ GLStateType.TEXTURE_STATE,
+ GLStateType.TEXTURE_UNITS,
+ Integer.valueOf(i),
+ GLStateType.TEXTURE_BINDING_2D),
+ Integer.valueOf(0), /* reset binding to texture 0 */
+ Predicates.matchesInteger(texture) /* only if currently bound to @texture */ ));
+ }
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlDeleteTextures(GLMessage msg) {
+ // void glDeleteTextures(GLsizei n, const GLuint * textures);
+ int n = msg.getArgs(0).getIntValue(0);
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>(n);
+ for (int i = 0; i < n; i++) {
+ int texture = msg.getArgs(1).getIntValue(i);
+ transforms.add(new SparseArrayElementRemoveTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TEXTURE_STATE,
+ GLStateType.TEXTURES),
+ texture));
+ transforms.addAll(transformsToResetBoundTextureUnits(msg.getContextId(), texture));
+ }
+
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlActiveTexture(GLMessage msg) {
+ // void glActiveTexture(GLenum texture);
+ GLEnum texture = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ Integer textureIndex = Integer.valueOf((int)(texture.value - GLEnum.GL_TEXTURE0.value));
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.TEXTURE_STATE,
+ GLStateType.ACTIVE_TEXTURE_UNIT),
+ textureIndex);
+ return Collections.singletonList(transform);
+ }
+
+ private static GLStateType getTextureUnitTargetName(GLEnum target) {
+ if (target == GLEnum.GL_TEXTURE_CUBE_MAP) {
+ return GLStateType.TEXTURE_BINDING_CUBE_MAP;
+ } else if (target == GLEnum.GL_TEXTURE_EXTERNAL) {
+ // added by OES_EGL_image_external
+ return GLStateType.TEXTURE_BINDING_EXTERNAL;
+ } else {
+ return GLStateType.TEXTURE_BINDING_2D;
+ }
+ }
+
+ private static GLStateType getTextureTargetName(GLEnum pname) {
+ switch (pname) {
+ case GL_TEXTURE_MIN_FILTER:
+ return GLStateType.TEXTURE_MIN_FILTER;
+ case GL_TEXTURE_MAG_FILTER:
+ return GLStateType.TEXTURE_MAG_FILTER;
+ case GL_TEXTURE_WRAP_S:
+ return GLStateType.TEXTURE_WRAP_S;
+ case GL_TEXTURE_WRAP_T:
+ return GLStateType.TEXTURE_WRAP_T;
+ }
+
+ assert false : "glTexParameter's pname argument does not support provided value.";
+ return GLStateType.TEXTURE_MIN_FILTER;
+ }
+
+ private static List<IStateTransform> transformsForGlBindTexture(GLMessage msg) {
+ // void glBindTexture(GLenum target, GLuint texture);
+ GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ Integer texture = Integer.valueOf(msg.getArgs(1).getIntValue(0));
+
+ IStateTransform transform = new PropertyChangeTransform(
+ new TextureUnitPropertyAccessor(msg.getContextId(),
+ getTextureUnitTargetName(target)),
+ texture);
+ return Collections.singletonList(transform);
+ }
+
+ /**
+ * Utility function used by both {@link #transformsForGlTexImage2D(GLMessage) and
+ * {@link #transformsForGlTexSubImage2D(GLMessage)}.
+ */
+ private static List<IStateTransform> transformsForGlTexImage(GLMessage msg, int widthArgIndex,
+ int heightArgIndex, int xOffsetIndex, int yOffsetIndex) {
+ GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ int level = msg.getArgs(1).getIntValue(0);
+ Integer width = Integer.valueOf(msg.getArgs(widthArgIndex).getIntValue(0));
+ Integer height = Integer.valueOf(msg.getArgs(heightArgIndex).getIntValue(0));
+ GLEnum format = GLEnum.valueOf(msg.getArgs(6).getIntValue(0));
+ GLEnum type = GLEnum.valueOf(msg.getArgs(7).getIntValue(0));
+
+ List<IStateTransform> transforms = new ArrayList<IStateTransform>();
+ transforms.add(new PropertyChangeTransform(
+ new TexturePropertyAccessor(msg.getContextId(),
+ getTextureUnitTargetName(target),
+ level,
+ GLStateType.TEXTURE_WIDTH),
+ width));
+ transforms.add(new PropertyChangeTransform(
+ new TexturePropertyAccessor(msg.getContextId(),
+ getTextureUnitTargetName(target),
+ level,
+ GLStateType.TEXTURE_HEIGHT),
+ height));
+ transforms.add(new PropertyChangeTransform(
+ new TexturePropertyAccessor(msg.getContextId(),
+ getTextureUnitTargetName(target),
+ level,
+ GLStateType.TEXTURE_FORMAT),
+ format));
+ transforms.add(new PropertyChangeTransform(
+ new TexturePropertyAccessor(msg.getContextId(),
+ getTextureUnitTargetName(target),
+ level,
+ GLStateType.TEXTURE_IMAGE_TYPE),
+ type));
+
+ // if texture data is available, extract and store it in the cache folder
+ File f = null;
+ if (msg.getArgs(8).getIsArray()) {
+ ByteString data = msg.getArgs(8).getRawBytes(0);
+ f = FileUtils.createTempFile(TEXTURE_DATA_FILE_PREFIX, TEXTURE_DATA_FILE_SUFFIX);
+ try {
+ Files.write(data.toByteArray(), f);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ int xOffset = 0;
+ int yOffset = 0;
+
+ if (xOffsetIndex >= 0) {
+ xOffset = msg.getArgs(xOffsetIndex).getIntValue(0);
+ }
+
+ if (yOffsetIndex >= 0) {
+ yOffset = msg.getArgs(yOffsetIndex).getIntValue(0);
+ }
+
+ transforms.add(new TexImageTransform(
+ new TexturePropertyAccessor(msg.getContextId(),
+ getTextureUnitTargetName(target),
+ level,
+ GLStateType.TEXTURE_IMAGE),
+ f, format, type, xOffset, yOffset, width, height));
+
+ return transforms;
+ }
+
+ private static List<IStateTransform> transformsForGlTexImage2D(GLMessage msg) {
+ // void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
+ // GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *data);
+ return transformsForGlTexImage(msg, 3, 4, -1, -1);
+ }
+
+ private static List<IStateTransform> transformsForGlTexSubImage2D(GLMessage msg) {
+ // void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ // GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data);
+ return transformsForGlTexImage(msg, 4, 5, 2, 3);
+ }
+
+ private static List<IStateTransform> transformsForGlTexParameter(GLMessage msg) {
+ // void glTexParameteri(GLenum target, GLenum pname, GLint param);
+ GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ GLEnum pname = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
+ GLEnum pvalue = GLEnum.valueOf(msg.getArgs(2).getIntValue(0));
+
+ if (sTexParameterPnameValues == null) {
+ GLEnum[] pnameValues = new GLEnum[] {
+ GLEnum.GL_TEXTURE_BASE_LEVEL,
+ GLEnum.GL_TEXTURE_COMPARE_FUNC,
+ GLEnum.GL_TEXTURE_COMPARE_MODE,
+ GLEnum.GL_TEXTURE_MIN_FILTER,
+ GLEnum.GL_TEXTURE_MAG_FILTER,
+ GLEnum.GL_TEXTURE_MIN_LOD,
+ GLEnum.GL_TEXTURE_MAX_LOD,
+ GLEnum.GL_TEXTURE_MAX_LEVEL,
+ GLEnum.GL_TEXTURE_SWIZZLE_R,
+ GLEnum.GL_TEXTURE_SWIZZLE_G,
+ GLEnum.GL_TEXTURE_SWIZZLE_B,
+ GLEnum.GL_TEXTURE_SWIZZLE_A,
+ GLEnum.GL_TEXTURE_WRAP_S,
+ GLEnum.GL_TEXTURE_WRAP_T,
+ GLEnum.GL_TEXTURE_WRAP_R
+ };
+ sTexParameterPnameValues = EnumSet.copyOf(Arrays.asList(pnameValues));
+ }
+
+ if (!sTexParameterPnameValues.contains(pname)) {
+ throw new IllegalArgumentException(
+ String.format("Unsupported parameter (%s) for glTexParameter()", pname));
+ }
+
+ IStateTransform transform = new PropertyChangeTransform(
+ new TexturePropertyAccessor(msg.getContextId(),
+ getTextureUnitTargetName(target),
+ getTextureTargetName(pname)),
+ pvalue);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlCreateProgram(GLMessage msg) {
+ // GLuint glCreateProgram(void);
+ int program = msg.getReturnValue().getIntValue(0);
+
+ IStateTransform transform = new SparseArrayElementAddTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PROGRAM_STATE,
+ GLStateType.PROGRAMS),
+ program);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlUseProgram(GLMessage msg) {
+ // void glUseProgram(GLuint program);
+ Integer program = Integer.valueOf(msg.getArgs(0).getIntValue(0));
+
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PROGRAM_STATE,
+ GLStateType.CURRENT_PROGRAM),
+ program);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlAttachShader(GLMessage msg) {
+ // void glAttachShader(GLuint program, GLuint shader);
+ int program = msg.getArgs(0).getIntValue(0);
+ int shader = msg.getArgs(1).getIntValue(0);
+
+ IStateTransform transform = new SparseArrayElementAddTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PROGRAM_STATE,
+ GLStateType.PROGRAMS,
+ Integer.valueOf(program),
+ GLStateType.ATTACHED_SHADERS),
+ Integer.valueOf(shader));
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlDetachShader(GLMessage msg) {
+ // void glDetachShader(GLuint program, GLuint shader);
+ int program = msg.getArgs(0).getIntValue(0);
+ int shader = msg.getArgs(1).getIntValue(0);
+
+ IStateTransform transform = new SparseArrayElementRemoveTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PROGRAM_STATE,
+ GLStateType.PROGRAMS,
+ Integer.valueOf(program),
+ GLStateType.ATTACHED_SHADERS),
+ Integer.valueOf(shader));
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlGetActiveAttribOrUniform(
+ GLMessage msg, boolean isAttrib) {
+ // void glGetActive[Attrib|Uniform](GLuint program, GLuint index, GLsizei bufsize,
+ // GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+ int program = msg.getArgs(0).getIntValue(0);
+ int size = msg.getArgs(4).getIntValue(0);
+ GLEnum type = GLEnum.valueOf(msg.getArgs(5).getIntValue(0));
+ String name = msg.getArgs(6).getCharValue(0).toStringUtf8();
+
+ // The 2nd argument (index) does not give the correct location of the
+ // attribute/uniform in device. The actual location is obtained from
+ // the getAttribLocation or getUniformLocation calls. The trace library
+ // appends this value as an additional last argument to this call.
+ int location = msg.getArgs(7).getIntValue(0);
+
+ GLStateType activeInput;
+ GLStateType inputName;
+ GLStateType inputType;
+ GLStateType inputSize;
+
+ if (isAttrib) {
+ activeInput = GLStateType.ACTIVE_ATTRIBUTES;
+ inputName = GLStateType.ATTRIBUTE_NAME;
+ inputType = GLStateType.ATTRIBUTE_TYPE;
+ inputSize = GLStateType.ATTRIBUTE_SIZE;
+ } else {
+ activeInput = GLStateType.ACTIVE_UNIFORMS;
+ inputName = GLStateType.UNIFORM_NAME;
+ inputType = GLStateType.UNIFORM_TYPE;
+ inputSize = GLStateType.UNIFORM_SIZE;
+ }
+
+ IStateTransform addAttribute = new SparseArrayElementAddTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PROGRAM_STATE,
+ GLStateType.PROGRAMS,
+ Integer.valueOf(program),
+ activeInput),
+ Integer.valueOf(location));
+ IStateTransform setAttributeName = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PROGRAM_STATE,
+ GLStateType.PROGRAMS,
+ Integer.valueOf(program),
+ activeInput,
+ Integer.valueOf(location),
+ inputName),
+ name);
+ IStateTransform setAttributeType = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PROGRAM_STATE,
+ GLStateType.PROGRAMS,
+ Integer.valueOf(program),
+ activeInput,
+ Integer.valueOf(location),
+ inputType),
+ type);
+ IStateTransform setAttributeSize = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.PROGRAM_STATE,
+ GLStateType.PROGRAMS,
+ Integer.valueOf(program),
+ activeInput,
+ Integer.valueOf(location),
+ inputSize),
+ Integer.valueOf(size));
+ return Arrays.asList(addAttribute, setAttributeName, setAttributeType, setAttributeSize);
+ }
+
+ private static List<IStateTransform> transformsForGlGetActiveAttrib(GLMessage msg) {
+ return transformsForGlGetActiveAttribOrUniform(msg, true);
+ }
+
+ private static List<IStateTransform> transformsForGlGetActiveUniform(GLMessage msg) {
+ return transformsForGlGetActiveAttribOrUniform(msg, false);
+ }
+
+ private static List<IStateTransform> transformsForGlUniformMatrix(GLMessage msg) {
+ // void glUniformMatrix[2|3|4]fv(GLint location, GLsizei count, GLboolean transpose,
+ // const GLfloat *value);
+ int location = msg.getArgs(0).getIntValue(0);
+ List<Float> uniforms = msg.getArgs(3).getFloatValueList();
+
+ IStateTransform setValues = new PropertyChangeTransform(
+ new CurrentProgramPropertyAccessor(msg.getContextId(),
+ GLStateType.ACTIVE_UNIFORMS,
+ location,
+ GLStateType.UNIFORM_VALUE),
+ uniforms);
+
+ return Collections.singletonList(setValues);
+ }
+
+ private static List<IStateTransform> transformsForGlUniformv(GLMessage msg, boolean isFloats) {
+ // void glUniform1fv(GLint location, GLsizei count, const GLfloat *value);
+ int location = msg.getArgs(0).getIntValue(0);
+ List<?> uniforms;
+ if (isFloats) {
+ uniforms = msg.getArgs(2).getFloatValueList();
+ } else {
+ uniforms = msg.getArgs(2).getIntValueList();
+ }
+
+ IStateTransform setValues = new PropertyChangeTransform(
+ new CurrentProgramPropertyAccessor(msg.getContextId(),
+ GLStateType.ACTIVE_UNIFORMS,
+ location,
+ GLStateType.UNIFORM_VALUE),
+ uniforms);
+
+ return Collections.singletonList(setValues);
+ }
+
+ private static List<IStateTransform> transformsForGlUniform(GLMessage msg, boolean isFloats) {
+ // void glUniform1f(GLint location, GLfloat v0);
+ // void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
+ // .. 3f
+ // .. 4f
+ // void glUniform1i(GLint location, GLfloat v0);
+ // void glUniform2i(GLint location, GLfloat v0, GLfloat v1);
+ // .. 3i
+ // .. 4i
+
+ int location = msg.getArgs(0).getIntValue(0);
+ if (location < 0) {
+ throw new IllegalArgumentException("Argument location cannot be less than 0.");
+ }
+ List<?> uniforms;
+ if (isFloats) {
+ List<Float> args = new ArrayList<Float>(msg.getArgsCount() - 1);
+ for (int i = 1; i < msg.getArgsCount(); i++) {
+ args.add(Float.valueOf(msg.getArgs(1).getFloatValue(0)));
+ }
+ uniforms = args;
+ } else {
+ List<Integer> args = new ArrayList<Integer>(msg.getArgsCount() - 1);
+ for (int i = 1; i < msg.getArgsCount(); i++) {
+ args.add(Integer.valueOf(msg.getArgs(1).getIntValue(0)));
+ }
+ uniforms = args;
+ }
+
+ IStateTransform setValues = new PropertyChangeTransform(
+ new CurrentProgramPropertyAccessor(msg.getContextId(),
+ GLStateType.ACTIVE_UNIFORMS,
+ location,
+ GLStateType.UNIFORM_VALUE),
+ uniforms);
+
+ return Collections.singletonList(setValues);
+ }
+
+ private static List<IStateTransform> transformsForGlCreateShader(GLMessage msg) {
+ // GLuint glCreateShader(GLenum shaderType);
+ GLEnum shaderType = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
+ int shader = msg.getReturnValue().getIntValue(0);
+
+ IStateTransform addShader = new SparseArrayElementAddTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.SHADERS),
+ shader);
+ IStateTransform setShaderType = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.SHADERS,
+ Integer.valueOf(shader),
+ GLStateType.SHADER_TYPE),
+ shaderType);
+ return Arrays.asList(addShader, setShaderType);
+ }
+
+ private static List<IStateTransform> transformsForGlDeleteShader(GLMessage msg) {
+ // void glDeleteShader(GLuint shader);
+ int shader = msg.getArgs(0).getIntValue(0);
+
+ IStateTransform transform = new SparseArrayElementRemoveTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.SHADERS),
+ shader);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForGlShaderSource(GLMessage msg) {
+ // void glShaderSource(GLuint shader, GLsizei count, const GLchar **string,
+ // const GLint *length);
+ // This message is patched up on the device to return a single string as opposed to a
+ // list of strings
+ int shader = msg.getArgs(0).getIntValue(0);
+ String src = msg.getArgs(2).getCharValue(0).toStringUtf8();
+
+ IStateTransform transform = new PropertyChangeTransform(
+ GLPropertyAccessor.makeAccessor(msg.getContextId(),
+ GLStateType.SHADERS,
+ Integer.valueOf(shader),
+ GLStateType.SHADER_SOURCE),
+ src);
+ return Collections.singletonList(transform);
+ }
+
+ private static List<IStateTransform> transformsForEglCreateContext(GLMessage msg) {
+ // void eglCreateContext(int version, int context);
+ int version = msg.getArgs(0).getIntValue(0);
+ IGLProperty glState = null;
+ if (version == 0) {
+ glState = GLState.createDefaultES1State();
+ } else {
+ glState = GLState.createDefaultES2State();
+ }
+ IStateTransform transform = new ListElementAddTransform(null, glState);
+ return Collections.singletonList(transform);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexImageTransform.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexImageTransform.java
new file mode 100644
index 000000000..dde89eae6
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexImageTransform.java
@@ -0,0 +1,342 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.FileUtils;
+import com.android.ide.eclipse.gltrace.GLEnum;
+import com.android.ide.eclipse.gltrace.state.GLStringProperty;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+import com.google.common.io.Files;
+import com.google.common.primitives.UnsignedBytes;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+
+import javax.imageio.ImageIO;
+
+/**
+ * {@link TexImageTransform} transforms the state to reflect the effect of a
+ * glTexImage2D or glTexSubImage2D GL call.
+ */
+public class TexImageTransform implements IStateTransform {
+ private static final String PNG_IMAGE_FORMAT = "PNG";
+ private static final String TEXTURE_FILE_PREFIX = "tex";
+ private static final String TEXTURE_FILE_SUFFIX = ".png";
+
+ private final IGLPropertyAccessor mAccessor;
+ private final File mTextureDataFile;
+
+ private final int mxOffset;
+ private final int myOffset;
+ private final int mWidth;
+ private final int mHeight;
+
+ private String mOldValue;
+ private String mNewValue;
+ private GLEnum mFormat;
+ private GLEnum mType;
+
+ /**
+ * Construct a texture image transformation.
+ * @param accessor accessor to obtain the GL state variable to modify
+ * @param textureData texture data passed in by the call. Could be null.
+ * @param format format of the source texture data
+ * @param xOffset x offset for the source data (used only in glTexSubImage2D)
+ * @param yOffset y offset for the source data (used only in glTexSubImage2D)
+ * @param width width of the texture
+ * @param height height of the texture
+ */
+ public TexImageTransform(IGLPropertyAccessor accessor, File textureData, GLEnum format,
+ GLEnum type, int xOffset, int yOffset, int width, int height) {
+ mAccessor = accessor;
+ mTextureDataFile = textureData;
+ mFormat = format;
+ mType = type;
+
+ mxOffset = xOffset;
+ myOffset = yOffset;
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public void apply(IGLProperty currentState) {
+ assert mOldValue == null : "Transform cannot be applied multiple times"; //$NON-NLS-1$
+
+ IGLProperty property = mAccessor.getProperty(currentState);
+ if (!(property instanceof GLStringProperty)) {
+ return;
+ }
+
+ GLStringProperty prop = (GLStringProperty) property;
+ mOldValue = prop.getStringValue();
+
+ // Applying texture transformations is a heavy weight process. So we perform
+ // it only once and save the result in a temporary file. The property is actually
+ // the path to the file.
+ if (mNewValue == null) {
+ try {
+ if (mOldValue == null) {
+ mNewValue = createTexture(mTextureDataFile, mWidth, mHeight);
+ } else {
+ mNewValue = updateTextureData(mOldValue, mTextureDataFile, mxOffset, myOffset,
+ mWidth, mHeight);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+
+ prop.setValue(mNewValue);
+ }
+
+ @Override
+ public void revert(IGLProperty state) {
+ if (mOldValue != null) {
+ IGLProperty property = mAccessor.getProperty(state);
+ property.setValue(mOldValue);
+ mOldValue = null;
+ }
+ }
+
+ @Override
+ public IGLProperty getChangedProperty(IGLProperty state) {
+ return mAccessor.getProperty(state);
+ }
+
+ /**
+ * Creates a texture of provided width and height. If the texture data file is provided,
+ * then the texture is initialized with the contents of that file, otherwise an empty
+ * image is created.
+ * @param textureDataFile path to texture data, could be null.
+ * @param width width of texture
+ * @param height height of texture
+ * @return path to cached texture
+ */
+ private String createTexture(File textureDataFile, int width, int height) throws IOException {
+ File f = FileUtils.createTempFile(TEXTURE_FILE_PREFIX, TEXTURE_FILE_SUFFIX);
+
+ BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
+
+ if (textureDataFile != null) {
+ byte[] initialData = Files.toByteArray(textureDataFile);
+ img.getRaster().setDataElements(0, 0, width, height,
+ formatSourceData(initialData, width, height));
+ }
+
+ ImageIO.write(img, PNG_IMAGE_FORMAT, f);
+
+ return f.getAbsolutePath();
+ }
+
+ /**
+ * Update part of an existing texture.
+ * @param currentImagePath current texture image.
+ * @param textureDataFile new data to update the current texture with
+ * @param xOffset x offset for the update region
+ * @param yOffset y offset for the update region
+ * @param width width of the update region
+ * @param height height of the update region
+ * @return path to the updated texture
+ */
+ private String updateTextureData(String currentImagePath, File textureDataFile,
+ int xOffset, int yOffset, int width, int height) throws IOException {
+ assert currentImagePath != null : "Attempt to update a null texture";
+
+ if (textureDataFile == null) {
+ // Do not perform any updates if we don't have the actual data.
+ return currentImagePath;
+ }
+
+ File f = FileUtils.createTempFile(TEXTURE_FILE_PREFIX, TEXTURE_FILE_SUFFIX);
+ BufferedImage image = null;
+ image = ImageIO.read(new File(currentImagePath));
+
+ byte[] subImageData = Files.toByteArray(textureDataFile);
+ image.getRaster().setDataElements(xOffset, yOffset, width, height,
+ formatSourceData(subImageData, width, height));
+ ImageIO.write(image, PNG_IMAGE_FORMAT, f);
+
+ return f.getAbsolutePath();
+ }
+
+ private byte[] formatSourceData(byte[] subImageData, int width, int height) {
+ if (mType != GLEnum.GL_UNSIGNED_BYTE) {
+ subImageData = unpackData(subImageData, mType);
+ }
+
+ switch (mFormat) {
+ case GL_RGBA:
+ // no conversions necessary
+ return subImageData;
+ case GL_RGB:
+ return addAlphaChannel(subImageData, width, height);
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ // GL_RED, GL_GREEN and GL_BLUE are all supposed to fill those respective
+ // channels, but we assume that the programmers intent was to use GL_ALPHA in order
+ // to overcome the issue that GL_ALPHA cannot be used with float data.
+ if (mType != GLEnum.GL_FLOAT) {
+ throw new RuntimeException();
+ } else {
+ // fall through - assume that it is GL_ALPHA
+ }
+ //$FALL-THROUGH$
+ case GL_ALPHA:
+ return addRGBChannels(subImageData, width, height);
+ case GL_LUMINANCE:
+ return createRGBAFromLuminance(subImageData, width, height);
+ case GL_LUMINANCE_ALPHA:
+ return createRGBAFromLuminanceAlpha(subImageData, width, height);
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ private byte[] unpackData(byte[] data, GLEnum type) {
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ return data;
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ return convertShortToUnsigned(data, 0xf000, 12, 0x0f00, 8, 0x00f0, 4, 0x000f, 0,
+ true);
+ case GL_UNSIGNED_SHORT_5_6_5:
+ return convertShortToUnsigned(data, 0xf800, 11, 0x07e0, 5, 0x001f, 0, 0, 0,
+ false);
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ return convertShortToUnsigned(data, 0xf800, 11, 0x07c0, 6, 0x003e, 1, 0x1, 0,
+ true);
+ case GL_FLOAT:
+ return convertFloatToUnsigned(data);
+ default:
+ return data;
+ }
+ }
+
+ private byte[] convertFloatToUnsigned(byte[] data) {
+ byte[] unsignedData = new byte[data.length];
+ ByteBuffer floatBuffer = ByteBuffer.wrap(data);
+ for (int i = 0; i < data.length / 4; i++) {
+ float v = floatBuffer.getFloat(i);
+ byte alpha = (byte)(v * 255);
+ unsignedData[i*4 + 3] = alpha;
+ }
+ return unsignedData;
+ }
+
+ private byte[] convertShortToUnsigned(byte[] shortData,
+ int rmask, int rshift,
+ int gmask, int gshift,
+ int bmask, int bshift,
+ int amask, int ashift,
+ boolean includeAlpha) {
+ int numChannels = includeAlpha ? 4 : 3;
+ byte[] unsignedData = new byte[(shortData.length/2) * numChannels];
+
+ for (int i = 0; i < (shortData.length / 2); i++) {
+ int hi = UnsignedBytes.toInt(shortData[i*2 + 0]);
+ int lo = UnsignedBytes.toInt(shortData[i*2 + 1]);
+
+ int x = hi << 8 | lo;
+
+ int r = (x & rmask) >>> rshift;
+ int g = (x & gmask) >>> gshift;
+ int b = (x & bmask) >>> bshift;
+ int a = (x & amask) >>> ashift;
+
+ unsignedData[i * numChannels + 0] = UnsignedBytes.checkedCast(r);
+ unsignedData[i * numChannels + 1] = UnsignedBytes.checkedCast(g);
+ unsignedData[i * numChannels + 2] = UnsignedBytes.checkedCast(b);
+
+ if (includeAlpha) {
+ unsignedData[i * numChannels + 3] = UnsignedBytes.checkedCast(a);
+ }
+ }
+
+ return unsignedData;
+ }
+
+ private byte[] addAlphaChannel(byte[] sourceData, int width, int height) {
+ assert sourceData.length == 3 * width * height; // should have R, G & B channels
+
+ byte[] data = new byte[4 * width * height];
+
+ for (int src = 0, dst = 0; src < sourceData.length; src += 3, dst += 4) {
+ data[dst + 0] = sourceData[src + 0]; // copy R byte
+ data[dst + 1] = sourceData[src + 1]; // copy G byte
+ data[dst + 2] = sourceData[src + 2]; // copy B byte
+ data[dst + 3] = 1; // add alpha = 1
+ }
+
+ return data;
+ }
+
+ private byte[] addRGBChannels(byte[] sourceData, int width, int height) {
+ assert sourceData.length == width * height; // should have a single alpha channel
+
+ byte[] data = new byte[4 * width * height];
+
+ for (int src = 0, dst = 0; src < sourceData.length; src++, dst += 4) {
+ data[dst + 0] = data[dst + 1] = data[dst + 2] = 0; // set R = G = B = 0
+ data[dst + 3] = sourceData[src]; // copy over alpha
+ }
+
+ return data;
+ }
+
+ private byte[] createRGBAFromLuminance(byte[] sourceData, int width, int height) {
+ assert sourceData.length == width * height; // should have a single luminance channel
+
+ byte[] data = new byte[4 * width * height];
+
+ for (int src = 0, dst = 0; src < sourceData.length; src++, dst += 4) {
+ int l = sourceData[src] * 3;
+ if (l > 255) { // clamp to 255
+ l = 255;
+ }
+
+ data[dst + 0] = data[dst + 1] = data[dst + 2] = (byte) l; // set R = G = B = L * 3
+ data[dst + 3] = 1; // set alpha = 1
+ }
+
+ return data;
+ }
+
+ private byte[] createRGBAFromLuminanceAlpha(byte[] sourceData, int width, int height) {
+ assert sourceData.length == 2 * width * height; // should have luminance & alpha channels
+
+ byte[] data = new byte[4 * width * height];
+
+ for (int src = 0, dst = 0; src < sourceData.length; src += 2, dst += 4) {
+ int l = sourceData[src] * 3;
+ if (l > 255) { // clamp to 255
+ l = 255;
+ }
+
+ data[dst + 0] = data[dst + 1] = data[dst + 2] = (byte) l; // set R = G = B = L * 3
+ data[dst + 3] = sourceData[src + 1]; // copy over alpha
+ }
+
+ return data;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexturePropertyAccessor.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexturePropertyAccessor.java
new file mode 100644
index 000000000..10758d819
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexturePropertyAccessor.java
@@ -0,0 +1,86 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.GLIntegerProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * The {@link TexturePropertyAccessor} provides the ability to access a
+ * texture property. Texture properties are accessed by first identifying the active
+ * texture unit ({@link GLStateType#ACTIVE_TEXTURE_UNIT}), and then identifying the texture
+ * that is bound to that unit.
+ */
+public class TexturePropertyAccessor implements IGLPropertyAccessor {
+ private final int mContextId;
+ private final GLStateType mTargetUnitType;
+ private final int mMipmapLevel;
+ private final GLStateType mTextureType;
+ private TextureUnitPropertyAccessor mTextureUnitPropertyAccessor;
+
+ public TexturePropertyAccessor(int contextId, GLStateType textureUnitTarget, int level,
+ GLStateType textureTargetName) {
+ mContextId = contextId;
+ mTargetUnitType = textureUnitTarget;
+ mMipmapLevel = level;
+ mTextureType = textureTargetName;
+ mTextureUnitPropertyAccessor = new TextureUnitPropertyAccessor(mContextId,
+ mTargetUnitType);
+ }
+
+ public TexturePropertyAccessor(int contextId, GLStateType textureUnitTarget,
+ GLStateType textureTargetName) {
+ this(contextId, textureUnitTarget, -1, textureTargetName);
+ }
+
+ @Override
+ public IGLProperty getProperty(IGLProperty state) {
+ // identify the texture that is bound in the current active texture unit
+ IGLProperty targetTexture = mTextureUnitPropertyAccessor.getProperty(state);
+ if (!(targetTexture instanceof GLIntegerProperty)) {
+ return null;
+ }
+ Integer textureId = (Integer) targetTexture.getValue();
+
+ // now extract the required property from the selected texture
+ IGLPropertyAccessor textureAccessor;
+ if (mMipmapLevel >= 0) {
+ textureAccessor = GLPropertyAccessor.makeAccessor(mContextId,
+ GLStateType.TEXTURE_STATE,
+ GLStateType.TEXTURES,
+ textureId,
+ GLStateType.TEXTURE_MIPMAPS,
+ Integer.valueOf(mMipmapLevel),
+ mTextureType);
+ } else {
+ textureAccessor = GLPropertyAccessor.makeAccessor(mContextId,
+ GLStateType.TEXTURE_STATE,
+ GLStateType.TEXTURES,
+ textureId,
+ mTextureType);
+ }
+
+ return textureAccessor.getProperty(state);
+ }
+
+ @Override
+ public String getPath() {
+ return String.format("TEXTURE_STATE/TEXTURES/${activeTexture}/%s", mTextureType);
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TextureUnitPropertyAccessor.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TextureUnitPropertyAccessor.java
new file mode 100644
index 000000000..2489e14db
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TextureUnitPropertyAccessor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.state.transforms;
+
+import com.android.ide.eclipse.gltrace.state.GLIntegerProperty;
+import com.android.ide.eclipse.gltrace.state.GLStateType;
+import com.android.ide.eclipse.gltrace.state.IGLProperty;
+
+/**
+ * The {@link TextureUnitPropertyAccessor} provides the ability to access a
+ * texture unit property that is indexed based on the run time value of the
+ * {@link GLStateType#ACTIVE_TEXTURE_UNIT} property.
+ */
+public class TextureUnitPropertyAccessor implements IGLPropertyAccessor {
+ private final int mContextId;
+ private final IGLPropertyAccessor mActiveTextureAccessor;
+ private final GLStateType mTargetType;
+
+ public TextureUnitPropertyAccessor(int contextId, GLStateType targetPropertyType) {
+ mContextId = contextId;
+ mTargetType = targetPropertyType;
+
+ mActiveTextureAccessor = GLPropertyAccessor.makeAccessor(mContextId,
+ GLStateType.TEXTURE_STATE,
+ GLStateType.ACTIVE_TEXTURE_UNIT);
+ }
+
+ @Override
+ public IGLProperty getProperty(IGLProperty state) {
+ // first extract the current active texture unit
+ IGLProperty activeTextureProperty = mActiveTextureAccessor.getProperty(state);
+ if (!(activeTextureProperty instanceof GLIntegerProperty)) {
+ return null;
+ }
+ Integer activeTexture = (Integer) activeTextureProperty.getValue();
+
+ // extract the required property for the current texture unit
+ IGLPropertyAccessor targetAccessor = GLPropertyAccessor.makeAccessor(mContextId,
+ GLStateType.TEXTURE_STATE,
+ GLStateType.TEXTURE_UNITS,
+ activeTexture,
+ mTargetType);
+ return targetAccessor.getProperty(state);
+ }
+
+ @Override
+ public String getPath() {
+ return String.format("TEXTURE_STATE/TEXTURE_UNITS/${activeTextureUnit}/%s", mTargetType);
+ }
+}
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();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/widgets/ImageCanvas.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/widgets/ImageCanvas.java
new file mode 100644
index 000000000..23baf1739
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/widgets/ImageCanvas.java
@@ -0,0 +1,250 @@
+/*
+ * 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.widgets;
+
+import com.android.ide.eclipse.gltrace.GlTracePlugin;
+
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.ErrorDialog;
+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.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ScrollBar;
+
+import java.io.File;
+
+public class ImageCanvas extends Canvas {
+ private static final int SCROLLBAR_INCREMENT = 20;
+
+ private Point mOrigin;
+
+ private ScrollBar mHorizontalScrollBar;
+ private ScrollBar mVerticalScrollBar;
+
+ private Image mImage;
+ private boolean mFitToCanvas;
+
+ public ImageCanvas(Composite parent) {
+ super(parent, SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL);
+ mOrigin = new Point(0, 0);
+
+ mHorizontalScrollBar = getHorizontalBar();
+ mVerticalScrollBar = getVerticalBar();
+
+ mFitToCanvas = true;
+
+ setScrollBarIncrements();
+ setScrollBarPageIncrements(getClientArea());
+
+ updateScrollBars();
+
+ SelectionListener scrollBarSelectionListener = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (e.getSource() == mHorizontalScrollBar) {
+ scrollHorizontally();
+ } else {
+ scrollVertically();
+ }
+ }
+ };
+
+ mHorizontalScrollBar.addSelectionListener(scrollBarSelectionListener);
+ mVerticalScrollBar.addSelectionListener(scrollBarSelectionListener);
+
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ setScrollBarPageIncrements(getClientArea());
+ updateScrollBars();
+ }
+ });
+
+ addListener(SWT.Paint, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ paintCanvas(e.gc);
+ }
+ });
+ }
+
+ public void setFitToCanvas(boolean en) {
+ mFitToCanvas = en;
+ updateScrollBars();
+ redraw();
+ }
+
+ public void setImage(Image image) {
+ if (mImage != null) {
+ mImage.dispose();
+ }
+
+ mImage = image;
+ mOrigin = new Point(0, 0);
+ updateScrollBars();
+ redraw();
+ }
+
+ private void updateScrollBars() {
+ Rectangle client = getClientArea();
+
+ int imageWidth, imageHeight;
+ if (mImage != null & !mFitToCanvas) {
+ imageWidth = mImage.getBounds().width;
+ imageHeight = mImage.getBounds().height;
+ } else {
+ imageWidth = client.width;
+ imageHeight = client.height;
+ }
+
+ mHorizontalScrollBar.setMaximum(imageWidth);
+ mVerticalScrollBar.setMaximum(imageHeight);
+ mHorizontalScrollBar.setThumb(Math.min(imageWidth, client.width));
+ mVerticalScrollBar.setThumb(Math.min(imageHeight, client.height));
+
+ int hPage = imageWidth - client.width;
+ int vPage = imageHeight - client.height;
+ int hSelection = mHorizontalScrollBar.getSelection();
+ int vSelection = mVerticalScrollBar.getSelection();
+ if (hSelection >= hPage) {
+ if (hPage <= 0) {
+ hSelection = 0;
+ }
+ mOrigin.x = -hSelection;
+ }
+
+ if (vSelection >= vPage) {
+ if (vPage <= 0) {
+ vSelection = 0;
+ }
+ mOrigin.y = -vSelection;
+ }
+
+ redraw();
+ }
+
+ private void setScrollBarPageIncrements(Rectangle clientArea) {
+ mHorizontalScrollBar.setPageIncrement(clientArea.width);
+ mVerticalScrollBar.setPageIncrement(clientArea.height);
+ }
+
+ private void setScrollBarIncrements() {
+ // The default increment is 1 pixel. Assign a saner default.
+ mHorizontalScrollBar.setIncrement(SCROLLBAR_INCREMENT);
+ mVerticalScrollBar.setIncrement(SCROLLBAR_INCREMENT);
+ }
+
+ private void scrollHorizontally() {
+ if (mImage == null) {
+ return;
+ }
+
+ int selection = mHorizontalScrollBar.getSelection();
+ int destX = -selection - mOrigin.x;
+ Rectangle imageBounds = mImage.getBounds();
+ scroll(destX, 0, 0, 0, imageBounds.width, imageBounds.height, false);
+ mOrigin.x = -selection;
+ }
+
+ private void scrollVertically() {
+ if (mImage == null) {
+ return;
+ }
+
+ int selection = mVerticalScrollBar.getSelection();
+ int destY = -selection - mOrigin.y;
+ Rectangle imageBounds = mImage.getBounds();
+ scroll(0, destY, 0, 0, imageBounds.width, imageBounds.height, false);
+ mOrigin.y = -selection;
+ }
+
+ private void paintCanvas(GC gc) {
+ gc.fillRectangle(getClientArea()); // clear entire client area
+ if (mImage == null) {
+ return;
+ }
+
+ Rectangle rect = mImage.getBounds();
+ Rectangle client = getClientArea();
+
+ if (mFitToCanvas && rect.width > 0 && rect.height > 0) {
+ double sx = (double) client.width / (double) rect.width;
+ double sy = (double) client.height / (double) rect.height;
+
+ if (sx < sy) {
+ // if we need to scale more horizontally, then reduce the client height
+ // appropriately so that aspect ratios are maintained
+ gc.drawImage(mImage,
+ 0, 0, rect.width, rect.height,
+ 0, 0, client.width, (int)(rect.height * sx));
+ drawBorder(gc, 0, 0, client.width, (int)(rect.height * sx));
+ } else {
+ // scale client width to maintain aspect ratio
+ gc.drawImage(mImage,
+ 0, 0, rect.width, rect.height,
+ 0, 0, (int)(rect.width * sy), client.height);
+ drawBorder(gc, 0, 0, (int)(rect.width * sy), client.height);
+ }
+ } else {
+ gc.drawImage(mImage, mOrigin.x, mOrigin.y);
+ drawBorder(gc, mOrigin.x, mOrigin.y, rect.width, rect.height);
+ }
+ }
+
+ private void drawBorder(GC gc, int x, int y, int width, int height) {
+ Color origFg = gc.getForeground();
+ gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
+ gc.drawRectangle(x, y, width, height);
+ gc.setForeground(origFg);
+ }
+
+ @Override
+ public void dispose() {
+ if (mImage != null && !mImage.isDisposed()) {
+ mImage.dispose();
+ }
+ }
+
+ public void exportImageTo(File file) {
+ if (mImage == null || file == null) {
+ return;
+ }
+
+ ImageLoader imageLoader = new ImageLoader();
+ imageLoader.data = new ImageData[] { mImage.getImageData() };
+
+ try {
+ imageLoader.save(file.getAbsolutePath(), SWT.IMAGE_PNG);
+ } catch (Exception e) {
+ ErrorDialog.openError(getShell(), "Save Image", "Error saving image",
+ new Status(Status.ERROR, GlTracePlugin.PLUGIN_ID, e.toString()));
+ }
+ }
+}