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