Home | History | Annotate | Download | only in transforms
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.gltrace.state.transforms;
     18 
     19 import com.android.ide.eclipse.gltrace.FileUtils;
     20 import com.android.ide.eclipse.gltrace.GLEnum;
     21 import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage;
     22 import com.android.ide.eclipse.gltrace.state.GLState;
     23 import com.android.ide.eclipse.gltrace.state.GLStateType;
     24 import com.android.ide.eclipse.gltrace.state.IGLProperty;
     25 import com.google.common.io.Files;
     26 import com.google.protobuf.ByteString;
     27 
     28 import java.io.File;
     29 import java.io.IOException;
     30 import java.util.ArrayList;
     31 import java.util.Arrays;
     32 import java.util.Collections;
     33 import java.util.List;
     34 
     35 public class StateTransformFactory {
     36     private static final String TEXTURE_DATA_FILE_PREFIX = "tex";   //$NON-NLS-1$
     37     private static final String TEXTURE_DATA_FILE_SUFFIX = ".dat";  //$NON-NLS-1$
     38 
     39     /** Construct a list of transformations to be applied for the provided OpenGL call. */
     40     public static List<IStateTransform> getTransformsFor(GLMessage msg) {
     41         switch (msg.getFunction()) {
     42             case eglCreateContext:
     43                 return transformsForEglCreateContext(msg);
     44             case glBindFramebuffer:
     45                 return transformsForGlBindFramebuffer(msg);
     46 
     47             // vertex data
     48             case glVertexAttribPointer:
     49                 return transformsForGlVertexAttribPointer(msg);
     50             case glVertexAttrib1f:
     51             case glVertexAttrib2f:
     52             case glVertexAttrib3f:
     53             case glVertexAttrib4f:
     54                 return transformsForGlVertexAttribxf(msg);
     55             case glVertexAttrib1fv:
     56             case glVertexAttrib2fv:
     57             case glVertexAttrib3fv:
     58             case glVertexAttrib4fv:
     59                 return transformsForGlVertexAttribxfv(msg);
     60             case glEnableVertexAttribArray:
     61                 return transformsForGlEnableVertexAttribArray(msg);
     62             case glDisableVertexAttribArray:
     63                 return transformsForGlDisableVertexAttribArray(msg);
     64 
     65             // VBO's
     66             case glBindBuffer:
     67                 return transformsForGlBindBuffer(msg);
     68             case glGenBuffers:
     69                 return transformsForGlGenBuffers(msg);
     70             case glDeleteBuffers:
     71                 return transformsForGlDeleteBuffers(msg);
     72             case glBufferData:
     73                 return transformsForGlBufferData(msg);
     74             case glBufferSubData:
     75                 return transformsForGlBufferSubData(msg);
     76 
     77             // transformation state
     78             case glViewport:
     79                 return transformsForGlViewport(msg);
     80             case glDepthRangef:
     81                 return transformsForGlDepthRangef(msg);
     82 
     83             // rasterization
     84             case glLineWidth:
     85                 return transformsForGlLineWidth(msg);
     86             case glCullFace:
     87                 return transformsForGlCullFace(msg);
     88             case glFrontFace:
     89                 return transformsForGlFrontFace(msg);
     90             case glPolygonOffset:
     91                 return transformsForGlPolygonOffset(msg);
     92 
     93             // pixel operations
     94             case glScissor:
     95                 return transformsForGlScissor(msg);
     96             case glStencilFunc:
     97                 return transformsForGlStencilFunc(msg);
     98             case glStencilFuncSeparate:
     99                 return transformsForGlStencilFuncSeparate(msg);
    100             case glStencilOp:
    101                 return transformsForGlStencilOp(msg);
    102             case glStencilOpSeparate:
    103                 return transformsForGlStencilOpSeparate(msg);
    104             case glDepthFunc:
    105                 return transformsForGlDepthFunc(msg);
    106             case glBlendEquation:
    107                 return transformsForGlBlendEquation(msg);
    108             case glBlendEquationSeparate:
    109                 return transformsForGlBlendEquationSeparate(msg);
    110             case glBlendFunc:
    111                 return transformsForGlBlendFunc(msg);
    112             case glBlendFuncSeparate:
    113                 return transformsForGlBlendFuncSeparate(msg);
    114             case glPixelStorei:
    115                 return transformsForGlPixelStorei(msg);
    116 
    117             // Texture State Transformations
    118             case glGenTextures:
    119                 return transformsForGlGenTextures(msg);
    120             case glDeleteTextures:
    121                 return transformsForGlDeleteTextures(msg);
    122             case glActiveTexture:
    123                 return transformsForGlActiveTexture(msg);
    124             case glBindTexture:
    125                 return transformsForGlBindTexture(msg);
    126             case glTexImage2D:
    127                 return transformsForGlTexImage2D(msg);
    128             case glTexSubImage2D:
    129                 return transformsForGlTexSubImage2D(msg);
    130             case glTexParameteri:
    131                 return transformsForGlTexParameter(msg);
    132 
    133             // Program State Transformations
    134             case glCreateProgram:
    135                 return transformsForGlCreateProgram(msg);
    136             case glUseProgram:
    137                 return transformsForGlUseProgram(msg);
    138             case glAttachShader:
    139                 return transformsForGlAttachShader(msg);
    140             case glDetachShader:
    141                 return transformsForGlDetachShader(msg);
    142             case glGetActiveAttrib:
    143                 return transformsForGlGetActiveAttrib(msg);
    144             case glGetActiveUniform:
    145                 return transformsForGlGetActiveUniform(msg);
    146             case glUniform1i:
    147             case glUniform2i:
    148             case glUniform3i:
    149             case glUniform4i:
    150                 return transformsForGlUniform(msg, false);
    151             case glUniform1f:
    152             case glUniform2f:
    153             case glUniform3f:
    154             case glUniform4f:
    155                 return transformsForGlUniform(msg, true);
    156             case glUniform1iv:
    157             case glUniform2iv:
    158             case glUniform3iv:
    159             case glUniform4iv:
    160                 return transformsForGlUniformv(msg, false);
    161             case glUniform1fv:
    162             case glUniform2fv:
    163             case glUniform3fv:
    164             case glUniform4fv:
    165                 return transformsForGlUniformv(msg, true);
    166             case glUniformMatrix2fv:
    167             case glUniformMatrix3fv:
    168             case glUniformMatrix4fv:
    169                 return transformsForGlUniformMatrix(msg);
    170 
    171             // Shader State Transformations
    172             case glCreateShader:
    173                 return transformsForGlCreateShader(msg);
    174             case glDeleteShader:
    175                 return transformsForGlDeleteShader(msg);
    176             case glShaderSource:
    177                 return transformsForGlShaderSource(msg);
    178             default:
    179                 return Collections.emptyList();
    180         }
    181     }
    182 
    183     private static List<IStateTransform> transformsForGlVertexAttribPointer(GLMessage msg) {
    184         int index = msg.getArgs(0).getIntValue(0);
    185 
    186         int size = msg.getArgs(1).getIntValue(0);
    187         int type = msg.getArgs(2).getIntValue(0);
    188         boolean normalized = msg.getArgs(3).getBoolValue(0);
    189         int stride = msg.getArgs(4).getIntValue(0);
    190         int pointer = msg.getArgs(5).getIntValue(0);
    191 
    192         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    193         transforms.add(new PropertyChangeTransform(
    194                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    195                                                 GLStateType.VERTEX_ARRAY_DATA,
    196                                                 GLStateType.VERTEX_ATTRIB_ARRAY,
    197                                                 Integer.valueOf(index),
    198                                                 GLStateType.VERTEX_ATTRIB_ARRAY_SIZE),
    199                 Integer.valueOf(size)));
    200         transforms.add(new PropertyChangeTransform(
    201                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    202                                                 GLStateType.VERTEX_ARRAY_DATA,
    203                                                 GLStateType.VERTEX_ATTRIB_ARRAY,
    204                                                 Integer.valueOf(index),
    205                                                 GLStateType.VERTEX_ATTRIB_ARRAY_TYPE),
    206                 GLEnum.valueOf(type)));
    207         transforms.add(new PropertyChangeTransform(
    208                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    209                                                 GLStateType.VERTEX_ARRAY_DATA,
    210                                                 GLStateType.VERTEX_ATTRIB_ARRAY,
    211                                                 Integer.valueOf(index),
    212                                                 GLStateType.VERTEX_ATTRIB_ARRAY_NORMALIZED),
    213                 Boolean.valueOf(normalized)));
    214         transforms.add(new PropertyChangeTransform(
    215                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    216                                                 GLStateType.VERTEX_ARRAY_DATA,
    217                                                 GLStateType.VERTEX_ATTRIB_ARRAY,
    218                                                 Integer.valueOf(index),
    219                                                 GLStateType.VERTEX_ATTRIB_ARRAY_STRIDE),
    220                 Integer.valueOf(stride)));
    221         transforms.add(new PropertyChangeTransform(
    222                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    223                                                 GLStateType.VERTEX_ARRAY_DATA,
    224                                                 GLStateType.VERTEX_ATTRIB_ARRAY,
    225                                                 Integer.valueOf(index),
    226                                                 GLStateType.VERTEX_ATTRIB_ARRAY_POINTER),
    227                 Integer.valueOf(pointer)));
    228         return transforms;
    229     }
    230 
    231     private static List<IStateTransform> transformsForGlVertexAttrib(int context,
    232             int index, float v0, float v1, float v2, float v3) {
    233         List<IStateTransform> transforms = new ArrayList<IStateTransform>(4);
    234         transforms.add(new PropertyChangeTransform(
    235                 GLPropertyAccessor.makeAccessor(context,
    236                                                 GLStateType.VERTEX_ARRAY_DATA,
    237                                                 GLStateType.GENERIC_VERTEX_ATTRIBUTES,
    238                                                 Integer.valueOf(index),
    239                                                 GLStateType.GENERIC_VERTEX_ATTRIB_V0),
    240                 Float.valueOf(v0)));
    241         transforms.add(new PropertyChangeTransform(
    242                 GLPropertyAccessor.makeAccessor(context,
    243                                                 GLStateType.VERTEX_ARRAY_DATA,
    244                                                 GLStateType.GENERIC_VERTEX_ATTRIBUTES,
    245                                                 Integer.valueOf(index),
    246                                                 GLStateType.GENERIC_VERTEX_ATTRIB_V1),
    247                 Float.valueOf(v1)));
    248         transforms.add(new PropertyChangeTransform(
    249                 GLPropertyAccessor.makeAccessor(context,
    250                                                 GLStateType.VERTEX_ARRAY_DATA,
    251                                                 GLStateType.GENERIC_VERTEX_ATTRIBUTES,
    252                                                 Integer.valueOf(index),
    253                                                 GLStateType.GENERIC_VERTEX_ATTRIB_V2),
    254                 Float.valueOf(v2)));
    255         transforms.add(new PropertyChangeTransform(
    256                 GLPropertyAccessor.makeAccessor(context,
    257                                                 GLStateType.VERTEX_ARRAY_DATA,
    258                                                 GLStateType.GENERIC_VERTEX_ATTRIBUTES,
    259                                                 Integer.valueOf(index),
    260                                                 GLStateType.GENERIC_VERTEX_ATTRIB_V3),
    261                 Float.valueOf(v3)));
    262         return transforms;
    263     }
    264 
    265     private static List<IStateTransform> transformsForGlVertexAttribxf(GLMessage msg) {
    266         // void glVertexAttrib1f(GLuint index, GLfloat v0);
    267         // void glVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1);
    268         // void glVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2);
    269         // void glVertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
    270 
    271         int index = msg.getArgs(0).getIntValue(0);
    272         float v0 = msg.getArgs(1).getFloatValue(0);
    273         float v1 = msg.getArgsCount() > 2 ? msg.getArgs(2).getFloatValue(0) : 0;
    274         float v2 = msg.getArgsCount() > 3 ? msg.getArgs(3).getFloatValue(0) : 0;
    275         float v3 = msg.getArgsCount() > 4 ? msg.getArgs(4).getFloatValue(0) : 0;
    276 
    277         return transformsForGlVertexAttrib(msg.getContextId(), index, v0, v1, v2, v3);
    278     }
    279 
    280     private static List<IStateTransform> transformsForGlVertexAttribxfv(GLMessage msg) {
    281         // void glVertexAttrib1fv(GLuint index, const GLfloat *v);
    282         // void glVertexAttrib2fv(GLuint index, const GLfloat *v);
    283         // void glVertexAttrib3fv(GLuint index, const GLfloat *v);
    284         // void glVertexAttrib4fv(GLuint index, const GLfloat *v);
    285 
    286         int index = msg.getArgs(0).getIntValue(0);
    287         float v[] = new float[4];
    288 
    289         for (int i = 0; i < msg.getArgs(1).getFloatValueList().size(); i++) {
    290             v[i] = msg.getArgs(1).getFloatValue(i);
    291         }
    292 
    293         return transformsForGlVertexAttrib(msg.getContextId(), index, v[0], v[1], v[2], v[3]);
    294     }
    295 
    296     private static List<IStateTransform> transformsForGlEnableVertexAttribArray(GLMessage msg) {
    297         // void glEnableVertexAttribArray(GLuint index);
    298         // void glDisableVertexAttribArray(GLuint index);
    299 
    300         int index = msg.getArgs(0).getIntValue(0);
    301         IStateTransform transform = new PropertyChangeTransform(
    302                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    303                                                 GLStateType.VERTEX_ARRAY_DATA,
    304                                                 GLStateType.VERTEX_ATTRIB_ARRAY,
    305                                                 Integer.valueOf(index),
    306                                                 GLStateType.VERTEX_ATTRIB_ARRAY_ENABLED),
    307                 Boolean.TRUE);
    308         return Collections.singletonList(transform);
    309     }
    310 
    311     private static List<IStateTransform> transformsForGlDisableVertexAttribArray(GLMessage msg) {
    312         // void glEnableVertexAttribArray(GLuint index);
    313         // void glDisableVertexAttribArray(GLuint index);
    314 
    315         int index = msg.getArgs(0).getIntValue(0);
    316         IStateTransform transform = new PropertyChangeTransform(
    317                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    318                                                 GLStateType.VERTEX_ARRAY_DATA,
    319                                                 GLStateType.VERTEX_ATTRIB_ARRAY,
    320                                                 Integer.valueOf(index),
    321                                                 GLStateType.VERTEX_ATTRIB_ARRAY_ENABLED),
    322                 Boolean.FALSE);
    323         return Collections.singletonList(transform);
    324     }
    325 
    326     private static List<IStateTransform> transformsForGlBindBuffer(GLMessage msg) {
    327         // void glBindBuffer(GLenum target, GLuint buffer);
    328         // target is one of GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER.
    329 
    330         GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    331         int buffer = msg.getArgs(1).getIntValue(0);
    332         GLStateType bufferType;
    333 
    334         if (target == GLEnum.GL_ARRAY_BUFFER) {
    335             bufferType = GLStateType.ARRAY_BUFFER_BINDING;
    336         } else {
    337             bufferType = GLStateType.ELEMENT_ARRAY_BUFFER_BINDING;
    338         }
    339 
    340         IStateTransform transform = new PropertyChangeTransform(
    341                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    342                                                 GLStateType.VERTEX_ARRAY_DATA,
    343                                                 GLStateType.BUFFER_BINDINGS,
    344                                                 bufferType),
    345                 Integer.valueOf(buffer));
    346         return Collections.singletonList(transform);
    347     }
    348 
    349     private static List<IStateTransform> transformsForGlGenBuffers(GLMessage msg) {
    350         // void glGenBuffers(GLsizei n, GLuint * buffers);
    351         int n = msg.getArgs(0).getIntValue(0);
    352         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    353 
    354         for (int i = 0; i < n; i++) {
    355             transforms.add(new SparseArrayElementAddTransform(
    356                     GLPropertyAccessor.makeAccessor(msg.getContextId(),
    357                                                     GLStateType.VERTEX_ARRAY_DATA,
    358                                                     GLStateType.VBO),
    359                     msg.getArgs(1).getIntValue(i)));
    360         }
    361 
    362         return transforms;
    363     }
    364 
    365     private static List<IStateTransform> transformsForGlDeleteBuffers(GLMessage msg) {
    366         // void glDeleteBuffers(GLsizei n, const GLuint * buffers);
    367         int n = msg.getArgs(0).getIntValue(0);
    368         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    369 
    370         for (int i = 0; i < n; i++) {
    371             transforms.add(new SparseArrayElementRemoveTransform(
    372                     GLPropertyAccessor.makeAccessor(msg.getContextId(),
    373                                                     GLStateType.VERTEX_ARRAY_DATA,
    374                                                     GLStateType.VBO),
    375                     msg.getArgs(1).getIntValue(i)));
    376         }
    377 
    378         return transforms;
    379     }
    380 
    381     private static List<IStateTransform> transformsForGlBufferData(GLMessage msg) {
    382         // void glBufferData(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage);
    383         GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    384         int size = msg.getArgs(1).getIntValue(0);
    385         byte[] data = null;
    386         GLEnum usage = GLEnum.valueOf(msg.getArgs(3).getIntValue(0));
    387 
    388         if (msg.getArgs(2).getRawBytesList().size() > 0) {
    389             data = msg.getArgs(2).getRawBytesList().get(0).toByteArray();
    390         } else {
    391             data = new byte[size];
    392         }
    393 
    394         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    395 
    396         transforms.add(new PropertyChangeTransform(
    397                 new CurrentVboPropertyAccessor(msg.getContextId(),
    398                                                target,
    399                                                GLStateType.BUFFER_SIZE),
    400                 Integer.valueOf(size)));
    401         transforms.add(new PropertyChangeTransform(
    402                 new CurrentVboPropertyAccessor(msg.getContextId(),
    403                                                target,
    404                                                GLStateType.BUFFER_DATA),
    405                 data));
    406         transforms.add(new PropertyChangeTransform(
    407                 new CurrentVboPropertyAccessor(msg.getContextId(),
    408                                                target,
    409                                                GLStateType.BUFFER_USAGE),
    410                 usage));
    411         transforms.add(new PropertyChangeTransform(
    412                 new CurrentVboPropertyAccessor(msg.getContextId(),
    413                                                target,
    414                                                GLStateType.BUFFER_TYPE),
    415                 target));
    416         return transforms;
    417     }
    418 
    419     private static List<IStateTransform> transformsForGlBufferSubData(GLMessage msg) {
    420         // void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);
    421         GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    422         int offset = msg.getArgs(1).getIntValue(0);
    423         byte[] data = msg.getArgs(3).getRawBytesList().get(0).toByteArray();
    424 
    425         IStateTransform transform = new BufferSubDataTransform(
    426                 new CurrentVboPropertyAccessor(msg.getContextId(),
    427                         target,
    428                         GLStateType.BUFFER_DATA),
    429                 offset, data);
    430 
    431         return Collections.singletonList(transform);
    432     }
    433 
    434     private static List<IStateTransform> transformsForGlBindFramebuffer(GLMessage msg) {
    435         // void glBindFramebuffer(GLenum target, GLuint framebuffer);
    436         int fb = msg.getArgs(1).getIntValue(0);
    437         IStateTransform transform = new PropertyChangeTransform(
    438                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    439                         GLStateType.FRAMEBUFFER_STATE,
    440                         GLStateType.FRAMEBUFFER_BINDING),
    441                 fb);
    442         return Collections.singletonList(transform);
    443     }
    444 
    445     private static List<IStateTransform> transformsForGlLineWidth(GLMessage msg) {
    446         // void glLineWidth(GLfloat width);
    447         float width = msg.getArgs(0).getFloatValue(0);
    448         IStateTransform transform = new PropertyChangeTransform(
    449                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    450                         GLStateType.RASTERIZATION_STATE,
    451                         GLStateType.LINE_WIDTH),
    452                 width);
    453         return Collections.singletonList(transform);
    454     }
    455 
    456     private static List<IStateTransform> transformsForGlCullFace(GLMessage msg) {
    457         // void glCullFace(GLenum mode);
    458         int mode = msg.getArgs(0).getIntValue(0);
    459         IStateTransform transform = new PropertyChangeTransform(
    460                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    461                         GLStateType.RASTERIZATION_STATE,
    462                         GLStateType.CULL_FACE_MODE),
    463                 GLEnum.valueOf(mode));
    464         return Collections.singletonList(transform);
    465     }
    466 
    467     private static List<IStateTransform> transformsForGlFrontFace(GLMessage msg) {
    468         // void glFrontFace(GLenum mode);
    469         int mode = msg.getArgs(0).getIntValue(0);
    470         IStateTransform transform = new PropertyChangeTransform(
    471                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    472                         GLStateType.RASTERIZATION_STATE,
    473                         GLStateType.FRONT_FACE),
    474                 GLEnum.valueOf(mode));
    475         return Collections.singletonList(transform);
    476     }
    477 
    478     private static List<IStateTransform> transformsForGlPolygonOffset(GLMessage msg) {
    479         // void glPolygonOffset(GLfloat factor, GLfloat units)
    480         float factor = msg.getArgs(0).getFloatValue(0);
    481         float units = msg.getArgs(1).getFloatValue(0);
    482 
    483         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    484         transforms.add(new PropertyChangeTransform(
    485                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    486                         GLStateType.RASTERIZATION_STATE,
    487                         GLStateType.POLYGON_OFFSET_FACTOR),
    488                 Float.valueOf(factor)));
    489         transforms.add(new PropertyChangeTransform(
    490                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    491                         GLStateType.RASTERIZATION_STATE,
    492                         GLStateType.POLYGON_OFFSET_UNITS),
    493                 Float.valueOf(units)));
    494         return transforms;
    495     }
    496 
    497     private static List<IStateTransform> transformsForGlScissor(GLMessage msg) {
    498         // void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
    499         int x = msg.getArgs(0).getIntValue(0);
    500         int y = msg.getArgs(1).getIntValue(0);
    501         int w = msg.getArgs(2).getIntValue(0);
    502         int h = msg.getArgs(3).getIntValue(0);
    503 
    504         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    505         transforms.add(new PropertyChangeTransform(
    506                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    507                         GLStateType.PIXEL_OPERATIONS,
    508                         GLStateType.SCISSOR_BOX,
    509                         GLStateType.SCISSOR_BOX_X),
    510                 Integer.valueOf(x)));
    511         transforms.add(new PropertyChangeTransform(
    512                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    513                         GLStateType.PIXEL_OPERATIONS,
    514                         GLStateType.SCISSOR_BOX,
    515                         GLStateType.SCISSOR_BOX_Y),
    516                 Integer.valueOf(y)));
    517         transforms.add(new PropertyChangeTransform(
    518                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    519                         GLStateType.PIXEL_OPERATIONS,
    520                         GLStateType.SCISSOR_BOX,
    521                         GLStateType.SCISSOR_BOX_WIDTH),
    522                 Integer.valueOf(w)));
    523         transforms.add(new PropertyChangeTransform(
    524                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    525                         GLStateType.PIXEL_OPERATIONS,
    526                         GLStateType.SCISSOR_BOX,
    527                         GLStateType.SCISSOR_BOX_HEIGHT),
    528                 Integer.valueOf(h)));
    529         return transforms;
    530     }
    531 
    532     private static List<IStateTransform> transformsForGlStencilFuncFront(int contextId,
    533             GLEnum func, int ref, int mask) {
    534         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    535         transforms.add(new PropertyChangeTransform(
    536                 GLPropertyAccessor.makeAccessor(contextId,
    537                         GLStateType.PIXEL_OPERATIONS,
    538                         GLStateType.STENCIL,
    539                         GLStateType.STENCIL_FUNC),
    540                 func));
    541         transforms.add(new PropertyChangeTransform(
    542                 GLPropertyAccessor.makeAccessor(contextId,
    543                         GLStateType.PIXEL_OPERATIONS,
    544                         GLStateType.STENCIL,
    545                         GLStateType.STENCIL_REF),
    546                 Integer.valueOf(ref)));
    547         transforms.add(new PropertyChangeTransform(
    548                 GLPropertyAccessor.makeAccessor(contextId,
    549                         GLStateType.PIXEL_OPERATIONS,
    550                         GLStateType.STENCIL,
    551                         GLStateType.STENCIL_VALUE_MASK),
    552                 Integer.valueOf(mask)));
    553         return transforms;
    554     }
    555 
    556     private static List<IStateTransform> transformsForGlStencilFuncBack(int contextId,
    557             GLEnum func, int ref, int mask) {
    558         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    559         transforms.add(new PropertyChangeTransform(
    560                 GLPropertyAccessor.makeAccessor(contextId,
    561                         GLStateType.PIXEL_OPERATIONS,
    562                         GLStateType.STENCIL,
    563                         GLStateType.STENCIL_BACK_FUNC),
    564                 func));
    565         transforms.add(new PropertyChangeTransform(
    566                 GLPropertyAccessor.makeAccessor(contextId,
    567                         GLStateType.PIXEL_OPERATIONS,
    568                         GLStateType.STENCIL,
    569                         GLStateType.STENCIL_BACK_REF),
    570                 Integer.valueOf(ref)));
    571         transforms.add(new PropertyChangeTransform(
    572                 GLPropertyAccessor.makeAccessor(contextId,
    573                         GLStateType.PIXEL_OPERATIONS,
    574                         GLStateType.STENCIL,
    575                         GLStateType.STENCIL_BACK_VALUE_MASK),
    576                 Integer.valueOf(mask)));
    577         return transforms;
    578     }
    579 
    580     private static List<IStateTransform> transformsForGlStencilFunc(GLMessage msg) {
    581         // void glStencilFunc(GLenum func, GLint ref, GLuint mask);
    582         GLEnum func = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    583         int ref = msg.getArgs(1).getIntValue(0);
    584         int mask = msg.getArgs(2).getIntValue(0);
    585 
    586         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    587         transforms.addAll(transformsForGlStencilFuncFront(msg.getContextId(), func, ref, mask));
    588         transforms.addAll(transformsForGlStencilFuncBack(msg.getContextId(), func, ref, mask));
    589         return transforms;
    590     }
    591 
    592     private static List<IStateTransform> transformsForGlStencilFuncSeparate(GLMessage msg) {
    593         // void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
    594         GLEnum face = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    595         GLEnum func = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
    596         int ref = msg.getArgs(2).getIntValue(0);
    597         int mask = msg.getArgs(3).getIntValue(0);
    598 
    599         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    600         if (face == GLEnum.GL_FRONT || face == GLEnum.GL_FRONT_AND_BACK) {
    601             transforms.addAll(
    602                     transformsForGlStencilFuncFront(msg.getContextId(), func, ref, mask));
    603         }
    604         if (face == GLEnum.GL_BACK || face == GLEnum.GL_FRONT_AND_BACK) {
    605             transforms.addAll(
    606                     transformsForGlStencilFuncBack(msg.getContextId(), func, ref, mask));
    607         }
    608 
    609         return transforms;
    610     }
    611 
    612     private static List<IStateTransform> transformsForGlStencilOpFront(int contextId,
    613             GLEnum sfail, GLEnum dpfail, GLEnum dppass) {
    614         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    615         transforms.add(new PropertyChangeTransform(
    616                 GLPropertyAccessor.makeAccessor(contextId,
    617                         GLStateType.PIXEL_OPERATIONS,
    618                         GLStateType.STENCIL,
    619                         GLStateType.STENCIL_FAIL),
    620                 sfail));
    621         transforms.add(new PropertyChangeTransform(
    622                 GLPropertyAccessor.makeAccessor(contextId,
    623                         GLStateType.PIXEL_OPERATIONS,
    624                         GLStateType.STENCIL,
    625                         GLStateType.STENCIL_PASS_DEPTH_FAIL),
    626                 dpfail));
    627         transforms.add(new PropertyChangeTransform(
    628                 GLPropertyAccessor.makeAccessor(contextId,
    629                         GLStateType.PIXEL_OPERATIONS,
    630                         GLStateType.STENCIL,
    631                         GLStateType.STENCIL_PASS_DEPTH_PASS),
    632                 dppass));
    633         return transforms;
    634     }
    635 
    636     private static List<IStateTransform> transformsForGlStencilOpBack(int contextId,
    637             GLEnum sfail, GLEnum dpfail, GLEnum dppass) {
    638         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    639         transforms.add(new PropertyChangeTransform(
    640                 GLPropertyAccessor.makeAccessor(contextId,
    641                         GLStateType.PIXEL_OPERATIONS,
    642                         GLStateType.STENCIL,
    643                         GLStateType.STENCIL_BACK_FAIL),
    644                 sfail));
    645         transforms.add(new PropertyChangeTransform(
    646                 GLPropertyAccessor.makeAccessor(contextId,
    647                         GLStateType.PIXEL_OPERATIONS,
    648                         GLStateType.STENCIL,
    649                         GLStateType.STENCIL_BACK_PASS_DEPTH_FAIL),
    650                 dpfail));
    651         transforms.add(new PropertyChangeTransform(
    652                 GLPropertyAccessor.makeAccessor(contextId,
    653                         GLStateType.PIXEL_OPERATIONS,
    654                         GLStateType.STENCIL,
    655                         GLStateType.STENCIL_BACK_PASS_DEPTH_PASS),
    656                 dppass));
    657         return transforms;
    658     }
    659 
    660     private static List<IStateTransform> transformsForGlStencilOp(GLMessage msg) {
    661         // void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
    662         GLEnum sfail = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    663         GLEnum dpfail = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
    664         GLEnum dppass = GLEnum.valueOf(msg.getArgs(2).getIntValue(0));
    665         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    666         transforms.addAll(
    667                 transformsForGlStencilOpFront(msg.getContextId(), sfail, dpfail, dppass));
    668         transforms.addAll(
    669                 transformsForGlStencilOpBack(msg.getContextId(), sfail, dpfail, dppass));
    670         return transforms;
    671     }
    672 
    673     private static List<IStateTransform> transformsForGlStencilOpSeparate(GLMessage msg) {
    674         // void glStencilOp(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
    675         GLEnum face = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    676         GLEnum sfail = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
    677         GLEnum dpfail = GLEnum.valueOf(msg.getArgs(2).getIntValue(0));
    678         GLEnum dppass = GLEnum.valueOf(msg.getArgs(3).getIntValue(0));
    679         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    680 
    681         if (face == GLEnum.GL_FRONT || face == GLEnum.GL_FRONT_AND_BACK) {
    682             transforms.addAll(
    683                     transformsForGlStencilOpFront(msg.getContextId(), sfail, dpfail, dppass));
    684         }
    685 
    686         if (face == GLEnum.GL_BACK || face == GLEnum.GL_FRONT_AND_BACK) {
    687             transforms.addAll(
    688                     transformsForGlStencilOpBack(msg.getContextId(), sfail, dpfail, dppass));
    689         }
    690 
    691         return transforms;
    692     }
    693 
    694     private static List<IStateTransform> transformsForGlDepthFunc(GLMessage msg) {
    695         // void glDepthFunc(GLenum func);
    696         GLEnum func = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    697 
    698         IStateTransform transform = new PropertyChangeTransform(
    699                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    700                         GLStateType.PIXEL_OPERATIONS,
    701                         GLStateType.DEPTH_FUNC),
    702                 func);
    703         return Collections.singletonList(transform);
    704     }
    705 
    706     private static IStateTransform transformForGlEquationRGB(int contextId, GLEnum mode) {
    707         return new PropertyChangeTransform(
    708                 GLPropertyAccessor.makeAccessor(contextId,
    709                         GLStateType.PIXEL_OPERATIONS,
    710                         GLStateType.BLEND,
    711                         GLStateType.BLEND_EQUATION_RGB),
    712                 mode);
    713     }
    714 
    715     private static IStateTransform transformForGlEquationAlpha(int contextId, GLEnum mode) {
    716         return new PropertyChangeTransform(
    717                 GLPropertyAccessor.makeAccessor(contextId,
    718                         GLStateType.PIXEL_OPERATIONS,
    719                         GLStateType.BLEND,
    720                         GLStateType.BLEND_EQUATION_ALPHA),
    721                 mode);
    722     }
    723 
    724     private static List<IStateTransform> transformsForGlBlendEquationSeparate(GLMessage msg) {
    725         // void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
    726         GLEnum rgb = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    727         GLEnum alpha = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
    728 
    729         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    730         transforms.add(transformForGlEquationRGB(msg.getContextId(), rgb));
    731         transforms.add(transformForGlEquationAlpha(msg.getContextId(), alpha));
    732         return transforms;
    733     }
    734 
    735     private static List<IStateTransform> transformsForGlBlendEquation(GLMessage msg) {
    736         // void glBlendEquation(GLenum mode);
    737         GLEnum mode = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    738 
    739         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    740         transforms.add(transformForGlEquationRGB(msg.getContextId(), mode));
    741         transforms.add(transformForGlEquationAlpha(msg.getContextId(), mode));
    742         return transforms;
    743     }
    744 
    745     private static List<IStateTransform> transformsForGlBlendFuncSrcDst(boolean src,
    746             int contextId, GLEnum rgb, GLEnum alpha) {
    747         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    748 
    749         GLStateType rgbAccessor = GLStateType.BLEND_DST_RGB;
    750         GLStateType alphaAccessor = GLStateType.BLEND_DST_ALPHA;
    751         if (src) {
    752             rgbAccessor = GLStateType.BLEND_SRC_RGB;
    753             alphaAccessor = GLStateType.BLEND_SRC_ALPHA;
    754         }
    755 
    756         transforms.add(new PropertyChangeTransform(
    757                 GLPropertyAccessor.makeAccessor(contextId,
    758                         GLStateType.PIXEL_OPERATIONS,
    759                         GLStateType.BLEND,
    760                         rgbAccessor),
    761                 rgb));
    762         transforms.add(new PropertyChangeTransform(
    763                 GLPropertyAccessor.makeAccessor(contextId,
    764                         GLStateType.PIXEL_OPERATIONS,
    765                         GLStateType.BLEND,
    766                         alphaAccessor),
    767                 alpha));
    768         return transforms;
    769     }
    770 
    771     private static List<IStateTransform> transformsForGlBlendFuncSeparate(GLMessage msg) {
    772         // void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
    773         GLEnum srcRgb = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    774         GLEnum dstRgb = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
    775         GLEnum srcAlpha = GLEnum.valueOf(msg.getArgs(2).getIntValue(0));
    776         GLEnum dstAlpha = GLEnum.valueOf(msg.getArgs(3).getIntValue(0));
    777 
    778         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    779         transforms.addAll(transformsForGlBlendFuncSrcDst(true,
    780                 msg.getContextId(), srcRgb, srcAlpha));
    781         transforms.addAll(transformsForGlBlendFuncSrcDst(false,
    782                 msg.getContextId(), dstRgb, dstAlpha));
    783         return transforms;
    784     }
    785 
    786     private static List<IStateTransform> transformsForGlBlendFunc(GLMessage msg) {
    787         // void glBlendFunc(GLenum sfactor, GLenum dfactor);
    788         GLEnum sfactor = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    789         GLEnum dfactor = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
    790 
    791         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    792         transforms.addAll(transformsForGlBlendFuncSrcDst(true,
    793                 msg.getContextId(), sfactor, sfactor));
    794         transforms.addAll(transformsForGlBlendFuncSrcDst(false,
    795                 msg.getContextId(), dfactor, dfactor));
    796         return transforms;
    797     }
    798 
    799     private static List<IStateTransform> transformsForGlPixelStorei(GLMessage msg) {
    800         // void glPixelStorei(GLenum pname, GLint param);
    801         GLEnum pname = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    802         Integer param = Integer.valueOf(msg.getArgs(1).getIntValue(0));
    803 
    804         IStateTransform transform;
    805         if (pname == GLEnum.GL_PACK_ALIGNMENT) {
    806             transform = new PropertyChangeTransform(
    807                     GLPropertyAccessor.makeAccessor(msg.getContextId(),
    808                             GLStateType.PIXEL_PACKING,
    809                             GLStateType.PACK_ALIGNMENT),
    810                     param);
    811         } else {
    812             transform = new PropertyChangeTransform(
    813                     GLPropertyAccessor.makeAccessor(msg.getContextId(),
    814                             GLStateType.PIXEL_PACKING,
    815                             GLStateType.UNPACK_ALIGNMENT),
    816                     param);
    817         }
    818 
    819         return Collections.singletonList(transform);
    820     }
    821 
    822     private static List<IStateTransform> transformsForGlViewport(GLMessage msg) {
    823         // void glViewport( GLint x, GLint y, GLsizei width, GLsizei height);
    824         int x = msg.getArgs(0).getIntValue(0);
    825         int y = msg.getArgs(1).getIntValue(0);
    826         int w = msg.getArgs(2).getIntValue(0);
    827         int h = msg.getArgs(3).getIntValue(0);
    828 
    829         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    830         transforms.add(new PropertyChangeTransform(
    831                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    832                                                 GLStateType.TRANSFORMATION_STATE,
    833                                                 GLStateType.VIEWPORT,
    834                                                 GLStateType.VIEWPORT_X),
    835                 Integer.valueOf(x)));
    836         transforms.add(new PropertyChangeTransform(
    837                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    838                                                 GLStateType.TRANSFORMATION_STATE,
    839                                                 GLStateType.VIEWPORT,
    840                                                 GLStateType.VIEWPORT_Y),
    841                 Integer.valueOf(y)));
    842         transforms.add(new PropertyChangeTransform(
    843                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    844                                                 GLStateType.TRANSFORMATION_STATE,
    845                                                 GLStateType.VIEWPORT,
    846                                                 GLStateType.VIEWPORT_WIDTH),
    847                 Integer.valueOf(w)));
    848         transforms.add(new PropertyChangeTransform(
    849                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    850                                                 GLStateType.TRANSFORMATION_STATE,
    851                                                 GLStateType.VIEWPORT,
    852                                                 GLStateType.VIEWPORT_HEIGHT),
    853                 Integer.valueOf(h)));
    854         return transforms;
    855     }
    856 
    857     private static List<IStateTransform> transformsForGlDepthRangef(GLMessage msg) {
    858         // void glDepthRangef(GLclampf nearVal, GLclampf farVal);
    859         float near = msg.getArgs(0).getFloatValue(0);
    860         float far = msg.getArgs(1).getFloatValue(0);
    861 
    862         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    863         transforms.add(new PropertyChangeTransform(
    864                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    865                                                 GLStateType.TRANSFORMATION_STATE,
    866                                                 GLStateType.DEPTH_RANGE,
    867                                                 GLStateType.DEPTH_RANGE_NEAR),
    868                 Float.valueOf(near)));
    869         transforms.add(new PropertyChangeTransform(
    870                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    871                                                 GLStateType.TRANSFORMATION_STATE,
    872                                                 GLStateType.DEPTH_RANGE,
    873                                                 GLStateType.DEPTH_RANGE_FAR),
    874                 Float.valueOf(far)));
    875         return transforms;
    876     }
    877 
    878     private static List<IStateTransform> transformsForGlGenTextures(GLMessage msg) {
    879         // void glGenTextures(GLsizei n, GLuint *textures);
    880         int n = msg.getArgs(0).getIntValue(0);
    881 
    882         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
    883         for (int i = 0; i < n; i++) {
    884             int texture = msg.getArgs(1).getIntValue(i);
    885             transforms.add(new SparseArrayElementAddTransform(
    886                     GLPropertyAccessor.makeAccessor(msg.getContextId(),
    887                                                     GLStateType.TEXTURE_STATE,
    888                                                     GLStateType.TEXTURES),
    889                     texture));
    890         }
    891 
    892         return transforms;
    893     }
    894 
    895     /**
    896      * Obtain a list of transforms that will reset any existing texture units
    897      * that are bound to provided texture.
    898      * @param contextId context to operate on
    899      * @param texture texture that should be unbound
    900      */
    901     private static List<IStateTransform> transformsToResetBoundTextureUnits(int contextId,
    902             int texture) {
    903         List<IStateTransform> transforms = new ArrayList<IStateTransform>(
    904                 GLState.TEXTURE_UNIT_COUNT);
    905 
    906         for (int i = 0; i < GLState.TEXTURE_UNIT_COUNT; i++) {
    907             transforms.add(new PropertyChangeTransform(
    908                     GLPropertyAccessor.makeAccessor(contextId,
    909                                                     GLStateType.TEXTURE_STATE,
    910                                                     GLStateType.TEXTURE_UNITS,
    911                                                     Integer.valueOf(i),
    912                                                     GLStateType.TEXTURE_BINDING_2D),
    913                     Integer.valueOf(0), /* reset binding to texture 0 */
    914                     Predicates.matchesInteger(texture) /* only if currently bound to @texture */ ));
    915         }
    916         return transforms;
    917     }
    918 
    919     private static List<IStateTransform> transformsForGlDeleteTextures(GLMessage msg) {
    920         // void glDeleteTextures(GLsizei n, const GLuint * textures);
    921         int n = msg.getArgs(0).getIntValue(0);
    922 
    923         List<IStateTransform> transforms = new ArrayList<IStateTransform>(n);
    924         for (int i = 0; i < n; i++) {
    925             int texture = msg.getArgs(1).getIntValue(i);
    926             transforms.add(new SparseArrayElementRemoveTransform(
    927                     GLPropertyAccessor.makeAccessor(msg.getContextId(),
    928                                                     GLStateType.TEXTURE_STATE,
    929                                                     GLStateType.TEXTURES),
    930                     texture));
    931             transforms.addAll(transformsToResetBoundTextureUnits(msg.getContextId(), texture));
    932         }
    933 
    934         return transforms;
    935     }
    936 
    937     private static List<IStateTransform> transformsForGlActiveTexture(GLMessage msg) {
    938         // void glActiveTexture(GLenum texture);
    939         GLEnum texture = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    940         Integer textureIndex = Integer.valueOf(texture.value - GLEnum.GL_TEXTURE0.value);
    941         IStateTransform transform = new PropertyChangeTransform(
    942                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
    943                                                 GLStateType.TEXTURE_STATE,
    944                                                 GLStateType.ACTIVE_TEXTURE_UNIT),
    945                 textureIndex);
    946         return Collections.singletonList(transform);
    947     }
    948 
    949     private static GLStateType getTextureUnitTargetName(GLEnum target) {
    950         if (target == GLEnum.GL_TEXTURE_CUBE_MAP) {
    951             return GLStateType.TEXTURE_BINDING_CUBE_MAP;
    952         } else if (target == GLEnum.GL_TEXTURE_EXTERNAL) {
    953             // added by OES_EGL_image_external
    954             return GLStateType.TEXTURE_BINDING_EXTERNAL;
    955         } else {
    956             return GLStateType.TEXTURE_BINDING_2D;
    957         }
    958     }
    959 
    960     private static GLStateType getTextureTargetName(GLEnum pname) {
    961         switch (pname) {
    962             case GL_TEXTURE_MIN_FILTER:
    963                 return GLStateType.TEXTURE_MIN_FILTER;
    964             case GL_TEXTURE_MAG_FILTER:
    965                 return GLStateType.TEXTURE_MAG_FILTER;
    966             case GL_TEXTURE_WRAP_S:
    967                 return GLStateType.TEXTURE_WRAP_S;
    968             case GL_TEXTURE_WRAP_T:
    969                 return GLStateType.TEXTURE_WRAP_T;
    970         }
    971 
    972         assert false : "glTexParameter's pname argument does not support provided value.";
    973         return GLStateType.TEXTURE_MIN_FILTER;
    974     }
    975 
    976     private static List<IStateTransform> transformsForGlBindTexture(GLMessage msg) {
    977         // void glBindTexture(GLenum target, GLuint texture);
    978         GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    979         Integer texture = Integer.valueOf(msg.getArgs(1).getIntValue(0));
    980 
    981         IStateTransform transform = new PropertyChangeTransform(
    982                 new TextureUnitPropertyAccessor(msg.getContextId(),
    983                                                 getTextureUnitTargetName(target)),
    984                 texture);
    985         return Collections.singletonList(transform);
    986     }
    987 
    988     /**
    989      * Utility function used by both {@link #transformsForGlTexImage2D(GLMessage) and
    990      * {@link #transformsForGlTexSubImage2D(GLMessage)}.
    991      */
    992     private static List<IStateTransform> transformsForGlTexImage(GLMessage msg, int widthArgIndex,
    993             int heightArgIndex, int xOffsetIndex, int yOffsetIndex) {
    994         GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
    995         int level = msg.getArgs(1).getIntValue(0);
    996         Integer width = Integer.valueOf(msg.getArgs(widthArgIndex).getIntValue(0));
    997         Integer height = Integer.valueOf(msg.getArgs(heightArgIndex).getIntValue(0));
    998         GLEnum format = GLEnum.valueOf(msg.getArgs(6).getIntValue(0));
    999         GLEnum type = GLEnum.valueOf(msg.getArgs(7).getIntValue(0));
   1000 
   1001         List<IStateTransform> transforms = new ArrayList<IStateTransform>();
   1002         transforms.add(new PropertyChangeTransform(
   1003                 new TexturePropertyAccessor(msg.getContextId(),
   1004                                             getTextureUnitTargetName(target),
   1005                                             level,
   1006                                             GLStateType.TEXTURE_WIDTH),
   1007                 width));
   1008         transforms.add(new PropertyChangeTransform(
   1009                 new TexturePropertyAccessor(msg.getContextId(),
   1010                                             getTextureUnitTargetName(target),
   1011                                             level,
   1012                                             GLStateType.TEXTURE_HEIGHT),
   1013                 height));
   1014         transforms.add(new PropertyChangeTransform(
   1015                 new TexturePropertyAccessor(msg.getContextId(),
   1016                                             getTextureUnitTargetName(target),
   1017                                             level,
   1018                                             GLStateType.TEXTURE_FORMAT),
   1019                 format));
   1020         transforms.add(new PropertyChangeTransform(
   1021                 new TexturePropertyAccessor(msg.getContextId(),
   1022                                             getTextureUnitTargetName(target),
   1023                                             level,
   1024                                             GLStateType.TEXTURE_IMAGE_TYPE),
   1025                 type));
   1026 
   1027         // if texture data is available, extract and store it in the cache folder
   1028         File f = null;
   1029         if (msg.getArgs(8).getIsArray()) {
   1030             ByteString data = msg.getArgs(8).getRawBytes(0);
   1031             f = FileUtils.createTempFile(TEXTURE_DATA_FILE_PREFIX, TEXTURE_DATA_FILE_SUFFIX);
   1032             try {
   1033                 Files.write(data.toByteArray(), f);
   1034             } catch (IOException e) {
   1035                 throw new RuntimeException(e);
   1036             }
   1037         }
   1038 
   1039         int xOffset = 0;
   1040         int yOffset = 0;
   1041 
   1042         if (xOffsetIndex >= 0) {
   1043             xOffset = msg.getArgs(xOffsetIndex).getIntValue(0);
   1044         }
   1045 
   1046         if (yOffsetIndex >= 0) {
   1047             yOffset = msg.getArgs(yOffsetIndex).getIntValue(0);
   1048         }
   1049 
   1050         transforms.add(new TexImageTransform(
   1051                 new TexturePropertyAccessor(msg.getContextId(),
   1052                         getTextureUnitTargetName(target),
   1053                         level,
   1054                         GLStateType.TEXTURE_IMAGE),
   1055                 f, format, type, xOffset, yOffset, width, height));
   1056 
   1057         return transforms;
   1058     }
   1059 
   1060     private static List<IStateTransform> transformsForGlTexImage2D(GLMessage msg) {
   1061         // void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
   1062         //          GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *data);
   1063         return transformsForGlTexImage(msg, 3, 4, -1, -1);
   1064     }
   1065 
   1066     private static List<IStateTransform> transformsForGlTexSubImage2D(GLMessage msg) {
   1067         // void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
   1068         //          GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data);
   1069         return transformsForGlTexImage(msg, 4, 5, 2, 3);
   1070     }
   1071 
   1072     private static List<IStateTransform> transformsForGlTexParameter(GLMessage msg) {
   1073         // void glTexParameteri(GLenum target, GLenum pname, GLint param);
   1074         GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
   1075         GLEnum pname = GLEnum.valueOf(msg.getArgs(1).getIntValue(0));
   1076         GLEnum pvalue = GLEnum.valueOf(msg.getArgs(2).getIntValue(0));
   1077 
   1078         if (pname != GLEnum.GL_TEXTURE_MIN_FILTER
   1079                 && pname != GLEnum.GL_TEXTURE_MAG_FILTER
   1080                 && pname != GLEnum.GL_TEXTURE_WRAP_S
   1081                 && pname != GLEnum.GL_TEXTURE_WRAP_T) {
   1082             throw new IllegalArgumentException(
   1083                     String.format("Unsupported parameter (%s) for glTexParameter()", pname));
   1084         }
   1085 
   1086         IStateTransform transform = new PropertyChangeTransform(
   1087                 new TexturePropertyAccessor(msg.getContextId(),
   1088                                             getTextureUnitTargetName(target),
   1089                                             getTextureTargetName(pname)),
   1090                 pvalue);
   1091         return Collections.singletonList(transform);
   1092     }
   1093 
   1094     private static List<IStateTransform> transformsForGlCreateProgram(GLMessage msg) {
   1095         // GLuint glCreateProgram(void);
   1096         int program = msg.getReturnValue().getIntValue(0);
   1097 
   1098         IStateTransform transform = new SparseArrayElementAddTransform(
   1099                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1100                                                 GLStateType.PROGRAM_STATE,
   1101                                                 GLStateType.PROGRAMS),
   1102                 program);
   1103         return Collections.singletonList(transform);
   1104     }
   1105 
   1106     private static List<IStateTransform> transformsForGlUseProgram(GLMessage msg) {
   1107         // void glUseProgram(GLuint program);
   1108         Integer program = Integer.valueOf(msg.getArgs(0).getIntValue(0));
   1109 
   1110         IStateTransform transform = new PropertyChangeTransform(
   1111                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1112                                                 GLStateType.PROGRAM_STATE,
   1113                                                 GLStateType.CURRENT_PROGRAM),
   1114                 program);
   1115         return Collections.singletonList(transform);
   1116     }
   1117 
   1118     private static List<IStateTransform> transformsForGlAttachShader(GLMessage msg) {
   1119         // void glAttachShader(GLuint program, GLuint shader);
   1120         int program = msg.getArgs(0).getIntValue(0);
   1121         int shader = msg.getArgs(1).getIntValue(0);
   1122 
   1123         IStateTransform transform = new SparseArrayElementAddTransform(
   1124                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1125                                                 GLStateType.PROGRAM_STATE,
   1126                                                 GLStateType.PROGRAMS,
   1127                                                 Integer.valueOf(program),
   1128                                                 GLStateType.ATTACHED_SHADERS),
   1129                 Integer.valueOf(shader));
   1130         return Collections.singletonList(transform);
   1131     }
   1132 
   1133     private static List<IStateTransform> transformsForGlDetachShader(GLMessage msg) {
   1134         // void glDetachShader(GLuint program, GLuint shader);
   1135         int program = msg.getArgs(0).getIntValue(0);
   1136         int shader = msg.getArgs(1).getIntValue(0);
   1137 
   1138         IStateTransform transform = new SparseArrayElementRemoveTransform(
   1139                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1140                                                 GLStateType.PROGRAM_STATE,
   1141                                                 GLStateType.PROGRAMS,
   1142                                                 Integer.valueOf(program),
   1143                                                 GLStateType.ATTACHED_SHADERS),
   1144                 Integer.valueOf(shader));
   1145         return Collections.singletonList(transform);
   1146     }
   1147 
   1148     private static List<IStateTransform> transformsForGlGetActiveAttribOrUniform(
   1149             GLMessage msg, boolean isAttrib) {
   1150         // void glGetActive[Attrib|Uniform](GLuint program, GLuint index, GLsizei bufsize,
   1151         //                  GLsizei* length, GLint* size, GLenum* type, GLchar* name);
   1152         int program = msg.getArgs(0).getIntValue(0);
   1153         int size = msg.getArgs(4).getIntValue(0);
   1154         GLEnum type = GLEnum.valueOf(msg.getArgs(5).getIntValue(0));
   1155         String name = msg.getArgs(6).getCharValue(0).toStringUtf8();
   1156 
   1157         // The 2nd argument (index) does not give the correct location of the
   1158         // attribute/uniform in device. The actual location is obtained from
   1159         // the getAttribLocation or getUniformLocation calls. The trace library
   1160         // appends this value as an additional last argument to this call.
   1161         int location = msg.getArgs(7).getIntValue(0);
   1162 
   1163         GLStateType activeInput;
   1164         GLStateType inputName;
   1165         GLStateType inputType;
   1166         GLStateType inputSize;
   1167 
   1168         if (isAttrib) {
   1169             activeInput = GLStateType.ACTIVE_ATTRIBUTES;
   1170             inputName = GLStateType.ATTRIBUTE_NAME;
   1171             inputType = GLStateType.ATTRIBUTE_TYPE;
   1172             inputSize = GLStateType.ATTRIBUTE_SIZE;
   1173         } else {
   1174             activeInput = GLStateType.ACTIVE_UNIFORMS;
   1175             inputName = GLStateType.UNIFORM_NAME;
   1176             inputType = GLStateType.UNIFORM_TYPE;
   1177             inputSize = GLStateType.UNIFORM_SIZE;
   1178         }
   1179 
   1180         IStateTransform addAttribute = new SparseArrayElementAddTransform(
   1181                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1182                                                 GLStateType.PROGRAM_STATE,
   1183                                                 GLStateType.PROGRAMS,
   1184                                                 Integer.valueOf(program),
   1185                                                 activeInput),
   1186                 Integer.valueOf(location));
   1187         IStateTransform setAttributeName = new PropertyChangeTransform(
   1188                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1189                                                 GLStateType.PROGRAM_STATE,
   1190                                                 GLStateType.PROGRAMS,
   1191                                                 Integer.valueOf(program),
   1192                                                 activeInput,
   1193                                                 Integer.valueOf(location),
   1194                                                 inputName),
   1195                 name);
   1196         IStateTransform setAttributeType = new PropertyChangeTransform(
   1197                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1198                                                 GLStateType.PROGRAM_STATE,
   1199                                                 GLStateType.PROGRAMS,
   1200                                                 Integer.valueOf(program),
   1201                                                 activeInput,
   1202                                                 Integer.valueOf(location),
   1203                                                 inputType),
   1204                 type);
   1205         IStateTransform setAttributeSize = new PropertyChangeTransform(
   1206                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1207                                                 GLStateType.PROGRAM_STATE,
   1208                                                 GLStateType.PROGRAMS,
   1209                                                 Integer.valueOf(program),
   1210                                                 activeInput,
   1211                                                 Integer.valueOf(location),
   1212                                                 inputSize),
   1213                 Integer.valueOf(size));
   1214         return Arrays.asList(addAttribute, setAttributeName, setAttributeType, setAttributeSize);
   1215     }
   1216 
   1217     private static List<IStateTransform> transformsForGlGetActiveAttrib(GLMessage msg) {
   1218         return transformsForGlGetActiveAttribOrUniform(msg, true);
   1219     }
   1220 
   1221     private static List<IStateTransform> transformsForGlGetActiveUniform(GLMessage msg) {
   1222         return transformsForGlGetActiveAttribOrUniform(msg, false);
   1223     }
   1224 
   1225     private static List<IStateTransform> transformsForGlUniformMatrix(GLMessage msg) {
   1226         // void glUniformMatrix[2|3|4]fv(GLint location, GLsizei count, GLboolean transpose,
   1227         //                                  const GLfloat *value);
   1228         int location = msg.getArgs(0).getIntValue(0);
   1229         List<Float> uniforms = msg.getArgs(3).getFloatValueList();
   1230 
   1231         IStateTransform setValues = new PropertyChangeTransform(
   1232                 new CurrentProgramPropertyAccessor(msg.getContextId(),
   1233                                                    GLStateType.ACTIVE_UNIFORMS,
   1234                                                    location,
   1235                                                    GLStateType.UNIFORM_VALUE),
   1236                 uniforms);
   1237 
   1238         return Collections.singletonList(setValues);
   1239     }
   1240 
   1241     private static List<IStateTransform> transformsForGlUniformv(GLMessage msg, boolean isFloats) {
   1242         // void glUniform1fv(GLint location, GLsizei count, const GLfloat *value);
   1243         int location = msg.getArgs(0).getIntValue(0);
   1244         List<?> uniforms;
   1245         if (isFloats) {
   1246             uniforms = msg.getArgs(2).getFloatValueList();
   1247         } else {
   1248             uniforms = msg.getArgs(2).getIntValueList();
   1249         }
   1250 
   1251         IStateTransform setValues = new PropertyChangeTransform(
   1252                 new CurrentProgramPropertyAccessor(msg.getContextId(),
   1253                                                    GLStateType.ACTIVE_UNIFORMS,
   1254                                                    location,
   1255                                                    GLStateType.UNIFORM_VALUE),
   1256                 uniforms);
   1257 
   1258         return Collections.singletonList(setValues);
   1259     }
   1260 
   1261     private static List<IStateTransform> transformsForGlUniform(GLMessage msg, boolean isFloats) {
   1262         // void glUniform1f(GLint location, GLfloat v0);
   1263         // void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
   1264         // ..            3f
   1265         // ..            4f
   1266         // void glUniform1i(GLint location, GLfloat v0);
   1267         // void glUniform2i(GLint location, GLfloat v0, GLfloat v1);
   1268         // ..            3i
   1269         // ..            4i
   1270 
   1271         int location = msg.getArgs(0).getIntValue(0);
   1272         if (location < 0) {
   1273             throw new IllegalArgumentException("Argument location cannot be less than 0.");
   1274         }
   1275         List<?> uniforms;
   1276         if (isFloats) {
   1277             List<Float> args = new ArrayList<Float>(msg.getArgsCount() - 1);
   1278             for (int i = 1; i < msg.getArgsCount(); i++) {
   1279                 args.add(Float.valueOf(msg.getArgs(1).getFloatValue(0)));
   1280             }
   1281             uniforms = args;
   1282         } else {
   1283             List<Integer> args = new ArrayList<Integer>(msg.getArgsCount() - 1);
   1284             for (int i = 1; i < msg.getArgsCount(); i++) {
   1285                 args.add(Integer.valueOf(msg.getArgs(1).getIntValue(0)));
   1286             }
   1287             uniforms = args;
   1288         }
   1289 
   1290         IStateTransform setValues = new PropertyChangeTransform(
   1291                 new CurrentProgramPropertyAccessor(msg.getContextId(),
   1292                                                    GLStateType.ACTIVE_UNIFORMS,
   1293                                                    location,
   1294                                                    GLStateType.UNIFORM_VALUE),
   1295                 uniforms);
   1296 
   1297         return Collections.singletonList(setValues);
   1298     }
   1299 
   1300     private static List<IStateTransform> transformsForGlCreateShader(GLMessage msg) {
   1301         // GLuint glCreateShader(GLenum shaderType);
   1302         GLEnum shaderType = GLEnum.valueOf(msg.getArgs(0).getIntValue(0));
   1303         int shader = msg.getReturnValue().getIntValue(0);
   1304 
   1305         IStateTransform addShader = new SparseArrayElementAddTransform(
   1306                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1307                                                 GLStateType.SHADERS),
   1308                 shader);
   1309         IStateTransform setShaderType = new PropertyChangeTransform(
   1310                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1311                                                 GLStateType.SHADERS,
   1312                                                 Integer.valueOf(shader),
   1313                                                 GLStateType.SHADER_TYPE),
   1314                 shaderType);
   1315         return Arrays.asList(addShader, setShaderType);
   1316     }
   1317 
   1318     private static List<IStateTransform> transformsForGlDeleteShader(GLMessage msg) {
   1319         // void glDeleteShader(GLuint shader);
   1320         int shader = msg.getArgs(0).getIntValue(0);
   1321 
   1322         IStateTransform transform = new SparseArrayElementRemoveTransform(
   1323                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1324                         GLStateType.SHADERS),
   1325                 shader);
   1326         return Collections.singletonList(transform);
   1327     }
   1328 
   1329     private static List<IStateTransform> transformsForGlShaderSource(GLMessage msg) {
   1330         // void glShaderSource(GLuint shader, GLsizei count, const GLchar **string,
   1331         //                                                          const GLint *length);
   1332         // This message is patched up on the device to return a single string as opposed to a
   1333         // list of strings
   1334         int shader = msg.getArgs(0).getIntValue(0);
   1335         String src = msg.getArgs(2).getCharValue(0).toStringUtf8();
   1336 
   1337         IStateTransform transform = new PropertyChangeTransform(
   1338                 GLPropertyAccessor.makeAccessor(msg.getContextId(),
   1339                                                 GLStateType.SHADERS,
   1340                                                 Integer.valueOf(shader),
   1341                                                 GLStateType.SHADER_SOURCE),
   1342                 src);
   1343         return Collections.singletonList(transform);
   1344     }
   1345 
   1346     private static List<IStateTransform> transformsForEglCreateContext(GLMessage msg) {
   1347         // void eglCreateContext(int version, int context);
   1348         int version = msg.getArgs(0).getIntValue(0);
   1349         IGLProperty glState = null;
   1350         if (version == 0) {
   1351             glState = GLState.createDefaultES1State();
   1352         } else {
   1353             glState = GLState.createDefaultES2State();
   1354         }
   1355         IStateTransform transform = new ListElementAddTransform(null, glState);
   1356         return Collections.singletonList(transform);
   1357     }
   1358 }
   1359