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. */
getTransformsFor(GLMessage msg)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 
transformsForGlVertexAttribPointer(GLMessage msg)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 
transformsForGlVertexAttrib(int context, int index, float v0, float v1, float v2, float v3)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 
transformsForGlVertexAttribxf(GLMessage msg)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 
transformsForGlVertexAttribxfv(GLMessage msg)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 
transformsForGlEnableVertexAttribArray(GLMessage msg)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 
transformsForGlDisableVertexAttribArray(GLMessage msg)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 
transformsForGlBindBuffer(GLMessage msg)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 
transformsForGlGenBuffers(GLMessage msg)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 
transformsForGlDeleteBuffers(GLMessage msg)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 
transformsForGlBufferData(GLMessage msg)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 
transformsForGlBufferSubData(GLMessage msg)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 
transformsForGlBindFramebuffer(GLMessage msg)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 
transformsForGlLineWidth(GLMessage msg)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 
transformsForGlCullFace(GLMessage msg)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 
transformsForGlFrontFace(GLMessage msg)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 
transformsForGlPolygonOffset(GLMessage msg)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 
transformsForGlScissor(GLMessage msg)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 
transformsForGlStencilFuncFront(int contextId, GLEnum func, int ref, int mask)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 
transformsForGlStencilFuncBack(int contextId, GLEnum func, int ref, int mask)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 
transformsForGlStencilFunc(GLMessage msg)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 
transformsForGlStencilFuncSeparate(GLMessage msg)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 
transformsForGlStencilOpFront(int contextId, GLEnum sfail, GLEnum dpfail, GLEnum dppass)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 
transformsForGlStencilOpBack(int contextId, GLEnum sfail, GLEnum dpfail, GLEnum dppass)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 
transformsForGlStencilOp(GLMessage msg)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 
transformsForGlStencilOpSeparate(GLMessage msg)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 
transformsForGlDepthFunc(GLMessage msg)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 
transformForGlEquationRGB(int contextId, GLEnum mode)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 
transformForGlEquationAlpha(int contextId, GLEnum mode)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 
transformsForGlBlendEquationSeparate(GLMessage msg)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 
transformsForGlBlendEquation(GLMessage msg)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 
transformsForGlBlendFuncSrcDst(boolean src, int contextId, GLEnum rgb, GLEnum alpha)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 
transformsForGlBlendFuncSeparate(GLMessage msg)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 
transformsForGlBlendFunc(GLMessage msg)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 
transformsForGlPixelStorei(GLMessage msg)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 
transformsForGlViewport(GLMessage msg)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 
transformsForGlDepthRangef(GLMessage msg)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 
transformsForGlGenTextures(GLMessage msg)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      */
transformsToResetBoundTextureUnits(int contextId, int texture)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 
transformsForGlDeleteTextures(GLMessage msg)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 
transformsForGlActiveTexture(GLMessage msg)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 
getTextureUnitTargetName(GLEnum target)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 
getTextureTargetName(GLEnum pname)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 
transformsForGlBindTexture(GLMessage msg)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      */
transformsForGlTexImage(GLMessage msg, int widthArgIndex, int heightArgIndex, int xOffsetIndex, int yOffsetIndex)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 
transformsForGlTexImage2D(GLMessage msg)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 
transformsForGlTexSubImage2D(GLMessage msg)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 
transformsForGlTexParameter(GLMessage msg)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 
transformsForGlCreateProgram(GLMessage msg)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 
transformsForGlUseProgram(GLMessage msg)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 
transformsForGlAttachShader(GLMessage msg)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 
transformsForGlDetachShader(GLMessage msg)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 
transformsForGlGetActiveAttribOrUniform( GLMessage msg, boolean isAttrib)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 
transformsForGlGetActiveAttrib(GLMessage msg)1243     private static List<IStateTransform> transformsForGlGetActiveAttrib(GLMessage msg) {
1244         return transformsForGlGetActiveAttribOrUniform(msg, true);
1245     }
1246 
transformsForGlGetActiveUniform(GLMessage msg)1247     private static List<IStateTransform> transformsForGlGetActiveUniform(GLMessage msg) {
1248         return transformsForGlGetActiveAttribOrUniform(msg, false);
1249     }
1250 
transformsForGlUniformMatrix(GLMessage msg)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 
transformsForGlUniformv(GLMessage msg, boolean isFloats)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 
transformsForGlUniform(GLMessage msg, boolean isFloats)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 
transformsForGlCreateShader(GLMessage msg)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 
transformsForGlDeleteShader(GLMessage msg)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 
transformsForGlShaderSource(GLMessage msg)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 
transformsForEglCreateContext(GLMessage msg)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