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