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