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