diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java | 1384 |
1 files changed, 1384 insertions, 0 deletions
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); + } +} |