aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/BufferSubDataTransform.java76
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentProgramPropertyAccessor.java67
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/CurrentVboPropertyAccessor.java71
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/GLPropertyAccessor.java139
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IGLPropertyAccessor.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IPredicate.java21
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/IStateTransform.java34
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/ListElementAddTransform.java69
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/Predicates.java36
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/PropertyChangeTransform.java103
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementAddTransform.java77
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/SparseArrayElementRemoveTransform.java49
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java1384
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexImageTransform.java342
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TexturePropertyAccessor.java86
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/TextureUnitPropertyAccessor.java64
16 files changed, 2649 insertions, 0 deletions
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);
+ }
+}