1 /*
2  * Copyright 2011, 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 #include <cutils/log.h>
18 #include <EGL/egldefs.h>
19 #include <GLES/gl.h>
20 #include <GLES/glext.h>
21 #include <GLES2/gl2.h>
22 #include <GLES2/gl2ext.h>
23 
24 #include "frameworks/native/opengl/libs/GLES_trace/proto/gltrace.pb.h"
25 #include "gltrace_api.h"
26 #include "gltrace_context.h"
27 #include "gltrace_fixup.h"
28 
29 namespace android {
30 namespace gltrace {
31 
glGetInteger(GLTraceContext * context,GLenum param)32 GLint glGetInteger(GLTraceContext *context, GLenum param) {
33     GLint x;
34     context->hooks->gl.glGetIntegerv(param, &x);
35     return x;
36 }
37 
glGetVertexAttrib(GLTraceContext * context,GLuint index,GLenum pname)38 GLint glGetVertexAttrib(GLTraceContext *context, GLuint index, GLenum pname) {
39     GLint x;
40     context->hooks->gl.glGetVertexAttribiv(index, pname, &x);
41     return x;
42 }
43 
isUsingPixelBuffers(GLTraceContext * context)44 bool isUsingPixelBuffers(GLTraceContext *context) {
45     if (context->getVersionMajor() < 3) {
46         return false; // PBOs not supported prior to GLES 3.0
47     }
48     return glGetInteger(context, GL_PIXEL_UNPACK_BUFFER_BINDING) != 0;
49 }
50 
isUsingArrayBuffers(GLTraceContext * context)51 bool isUsingArrayBuffers(GLTraceContext *context) {
52     return glGetInteger(context, GL_ARRAY_BUFFER_BINDING) != 0;
53 }
54 
isUsingElementArrayBuffers(GLTraceContext * context)55 bool isUsingElementArrayBuffers(GLTraceContext *context) {
56     return glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING) != 0;
57 }
58 
getBytesPerTexel(const GLenum format,const GLenum type)59 unsigned getBytesPerTexel(const GLenum format, const GLenum type) {
60     /*
61     Description from glTexImage2D spec:
62 
63     Data is read from data as a sequence of unsigned bytes or shorts, depending on type.
64     When type is GL_UNSIGNED_BYTE, each of the bytes is interpreted as one color component.
65     When type is one of GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, or
66     GL_UNSIGNED_SHORT_5_5_5_1, each unsigned short value is interpreted as containing all
67     the components for a single texel, with the color components arranged according to
68     format. Color components are treated as groups of one, two, three, or four values,
69     again based on format. Groups of components are referred to as texels.
70 
71     width × height texels are read from memory, starting at location data. By default,
72     these texels are taken from adjacent memory locations, except that after all width
73     texels are read, the read pointer is advanced to the next four-byte boundary.
74     The four-byte row alignment is specified by glPixelStorei with argument
75     GL_UNPACK_ALIGNMENT, and it can be set to one, two, four, or eight bytes.
76     */
77 
78     switch (type) {
79     case GL_UNSIGNED_SHORT_5_6_5:
80     case GL_UNSIGNED_SHORT_4_4_4_4:
81     case GL_UNSIGNED_SHORT_5_5_5_1:
82         return 2;
83     case GL_UNSIGNED_BYTE:
84         break;
85     default:
86         ALOGE("GetBytesPerPixel: unknown type %x", type);
87     }
88 
89     switch (format) {
90     case GL_ALPHA:
91     case GL_LUMINANCE:
92         return 1;
93     case GL_LUMINANCE_ALPHA:
94         return 2;
95     case GL_RGB:
96         return 3;
97     case GL_RGBA:
98     case 0x80E1: // GL_BGRA_EXT
99         return 4;
100     default:
101         ALOGE("GetBytesPerPixel: unknown format %x", format);
102     }
103 
104     return 1;   // in doubt...
105 }
106 
fixup_GenericFloatArray(int argIndex,int nFloats,GLMessage * glmsg,void * src)107 void fixup_GenericFloatArray(int argIndex, int nFloats, GLMessage *glmsg, void *src) {
108     GLMessage_DataType *arg_floatarray = glmsg->mutable_args(argIndex);
109     GLfloat *floatp = (GLfloat *)src;
110 
111     if (floatp == NULL) {
112         return;
113     }
114 
115     arg_floatarray->set_type(GLMessage::DataType::FLOAT);
116     arg_floatarray->set_isarray(true);
117     arg_floatarray->clear_floatvalue();
118 
119     for (int i = 0; i < nFloats; i++, floatp++) {
120         arg_floatarray->add_floatvalue(*floatp);
121     }
122 }
123 
fixup_GenericIntArray(int argIndex,int nInts,GLMessage * glmsg,void * src)124 void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg, void *src) {
125     GLMessage_DataType *arg_intarray = glmsg->mutable_args(argIndex);
126     GLint *intp = (GLint *)src;
127 
128     if (intp == NULL) {
129         return;
130     }
131 
132     arg_intarray->set_type(GLMessage::DataType::INT);
133     arg_intarray->set_isarray(true);
134     arg_intarray->clear_intvalue();
135 
136     for (int i = 0; i < nInts; i++, intp++) {
137         arg_intarray->add_intvalue(*intp);
138     }
139 }
140 
fixup_GenericEnumArray(int argIndex,int nEnums,GLMessage * glmsg,void * src)141 void fixup_GenericEnumArray(int argIndex, int nEnums, GLMessage *glmsg, void *src) {
142     // fixup as if they were ints
143     fixup_GenericIntArray(argIndex, nEnums, glmsg, src);
144 
145     // and then set the data type to be enum
146     GLMessage_DataType *arg_enumarray = glmsg->mutable_args(argIndex);
147     arg_enumarray->set_type(GLMessage::DataType::ENUM);
148 }
149 
150 /** Generic helper function: extract pointer at argIndex and
151     replace it with the C style string at *pointer */
fixup_CStringPtr(int argIndex,GLMessage * glmsg,void * src)152 void fixup_CStringPtr(int argIndex, GLMessage *glmsg, void *src) {
153     GLMessage_DataType *arg = glmsg->mutable_args(argIndex);
154     GLchar *ptr = (GLchar *) src;
155 
156     arg->set_type(GLMessage::DataType::CHAR);
157     arg->set_isarray(true);
158     arg->add_charvalue(ptr);
159 }
160 
fixup_glGetString(GLMessage * glmsg,void * pointersToFixup[])161 void fixup_glGetString(GLMessage *glmsg, void *pointersToFixup[]) {
162     /* const GLubyte* GLTrace_glGetString(GLenum name) */
163     GLMessage_DataType *ret = glmsg->mutable_returnvalue();
164     GLchar *ptr = (GLchar *) pointersToFixup[0];
165 
166     if (ptr != NULL) {
167         ret->set_type(GLMessage::DataType::CHAR);
168         ret->set_isarray(true);
169         ret->add_charvalue(ptr);
170     }
171 }
172 
173 /* Add the contents of the framebuffer to the protobuf message */
fixup_addFBContents(GLTraceContext * context,GLMessage * glmsg,FBBinding fbToRead)174 void fixup_addFBContents(GLTraceContext *context, GLMessage *glmsg, FBBinding fbToRead) {
175     void *fbcontents;
176     unsigned fbsize, fbwidth, fbheight;
177     context->getCompressedFB(&fbcontents, &fbsize, &fbwidth, &fbheight, fbToRead);
178 
179     GLMessage_FrameBuffer *fb = glmsg->mutable_fb();
180     fb->set_width(fbwidth);
181     fb->set_height(fbheight);
182     fb->add_contents(fbcontents, fbsize);
183 }
184 
185 /** Common fixup routing for glTexImage2D & glTexSubImage2D. */
fixup_glTexImage(GLTraceContext * context,int widthIndex,int heightIndex,GLMessage * glmsg,void * dataSrc)186 void fixup_glTexImage(GLTraceContext *context, int widthIndex, int heightIndex, GLMessage *glmsg,
187                         void *dataSrc) {
188     GLMessage_DataType arg_width  = glmsg->args(widthIndex);
189     GLMessage_DataType arg_height = glmsg->args(heightIndex);
190 
191     GLMessage_DataType arg_format = glmsg->args(6);
192     GLMessage_DataType arg_type   = glmsg->args(7);
193     GLMessage_DataType *arg_data  = glmsg->mutable_args(8);
194 
195     GLsizei width  = arg_width.intvalue(0);
196     GLsizei height = arg_height.intvalue(0);
197     GLenum format  = arg_format.intvalue(0);
198     GLenum type    = arg_type.intvalue(0);
199     void *data     = (void *) dataSrc;
200 
201     int bytesPerTexel = getBytesPerTexel(format, type);
202 
203     arg_data->set_type(GLMessage::DataType::BYTE);
204     arg_data->clear_rawbytes();
205 
206     if (data != NULL && !isUsingPixelBuffers(context)) {
207         arg_data->set_isarray(true);
208         arg_data->add_rawbytes(data, bytesPerTexel * width * height);
209     } else {
210         arg_data->set_isarray(false);
211         arg_data->set_type(GLMessage::DataType::VOID);
212     }
213 }
214 
215 
fixup_glTexImage2D(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])216 void fixup_glTexImage2D(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
217     /* void glTexImage2D(GLenum target,
218                         GLint level,
219                         GLint internalformat,
220                         GLsizei width,
221                         GLsizei height,
222                         GLint border,
223                         GLenum format,
224                         GLenum type,
225                         const GLvoid *data);
226     */
227     int widthIndex = 3;
228     int heightIndex = 4;
229     fixup_glTexImage(context, widthIndex, heightIndex, glmsg, pointersToFixup[0]);
230 }
231 
fixup_glTexSubImage2D(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])232 void fixup_glTexSubImage2D(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
233     /*
234     void glTexSubImage2D(GLenum target,
235                         GLint level,
236                         GLint xoffset,
237                         GLint yoffset,
238                         GLsizei width,
239                         GLsizei height,
240                         GLenum format,
241                         GLenum type,
242                         const GLvoid * data);
243     */
244     int widthIndex = 4;
245     int heightIndex = 5;
246     fixup_glTexImage(context, widthIndex, heightIndex, glmsg, pointersToFixup[0]);
247 }
248 
fixup_glCompressedTexImage2D(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])249 void fixup_glCompressedTexImage2D(GLTraceContext *context, GLMessage *glmsg,
250                                     void *pointersToFixup[]) {
251     /* void glCompressedTexImage2D(GLenum target,
252                                    GLint level,
253                                    GLenum internalformat,
254                                    GLsizei width,
255                                    GLsizei height,
256                                    GLint border,
257                                    GLsizei imageSize,
258                                    const GLvoid* data);
259     */
260     GLsizei size  = glmsg->args(6).intvalue(0);
261     void *data = pointersToFixup[0];
262 
263     GLMessage_DataType *arg_data  = glmsg->mutable_args(7);
264     arg_data->set_type(GLMessage::DataType::BYTE);
265     arg_data->clear_rawbytes();
266 
267     if (data != NULL && !isUsingPixelBuffers(context)) {
268         arg_data->set_isarray(true);
269         arg_data->add_rawbytes(data, size);
270     } else {
271         arg_data->set_isarray(false);
272         arg_data->set_type(GLMessage::DataType::VOID);
273     }
274 }
275 
fixup_glCompressedTexSubImage2D(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])276 void fixup_glCompressedTexSubImage2D(GLTraceContext *context, GLMessage *glmsg,
277                                         void *pointersToFixup[]) {
278     /* void glCompressedTexSubImage2D(GLenum target,
279                                       GLint level,
280                                       GLint xoffset,
281                                       GLint yoffset,
282                                       GLsizei width,
283                                       GLsizei height,
284                                       GLenum format,
285                                       GLsizei imageSize,
286                                       const GLvoid* data);
287     */
288     GLsizei size  = glmsg->args(7).intvalue(0);
289     void *data = pointersToFixup[0];
290 
291     GLMessage_DataType *arg_data  = glmsg->mutable_args(8);
292     arg_data->set_type(GLMessage::DataType::BYTE);
293     arg_data->clear_rawbytes();
294 
295     if (data != NULL && !isUsingPixelBuffers(context)) {
296         arg_data->set_isarray(true);
297         arg_data->add_rawbytes(data, size);
298     } else {
299         arg_data->set_isarray(false);
300         arg_data->set_type(GLMessage::DataType::VOID);
301     }
302 }
303 
fixup_glShaderSource(GLMessage * glmsg,void * pointersToFixup[])304 void fixup_glShaderSource(GLMessage *glmsg, void *pointersToFixup[]) {
305     /* void glShaderSource(GLuint shader, GLsizei count, const GLchar** string,
306                                     const GLint* length) */
307     GLMessage_DataType arg_count  = glmsg->args(1);
308     GLMessage_DataType arg_lenp   = glmsg->args(3);
309     GLMessage_DataType *arg_strpp = glmsg->mutable_args(2);
310 
311     GLsizei count = arg_count.intvalue(0);
312     GLchar **stringpp = (GLchar **) pointersToFixup[0];
313     GLint *lengthp = (GLint *) pointersToFixup[1];
314 
315     arg_strpp->set_type(GLMessage::DataType::CHAR);
316     arg_strpp->set_isarray(true);
317     arg_strpp->clear_charvalue();
318 
319     ::std::string src = "";
320     for (int i = 0; i < count; i++) {
321         if (lengthp != NULL)
322             src.append(*stringpp++, *lengthp++);
323         else
324             src.append(*stringpp++);  // assume null terminated
325     }
326 
327     arg_strpp->add_charvalue(src);
328 }
329 
fixup_glUniformGenericInteger(int argIndex,int nElemsPerVector,GLMessage * glmsg,void * pointersToFixup[])330 void fixup_glUniformGenericInteger(int argIndex, int nElemsPerVector, GLMessage *glmsg,
331                                                                     void *pointersToFixup[]) {
332     /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */
333     GLMessage_DataType arg_count  = glmsg->args(1);
334     int n_vectors = arg_count.intvalue(0);
335     fixup_GenericIntArray(argIndex, nElemsPerVector * n_vectors, glmsg, pointersToFixup[0]);
336 }
337 
fixup_glUniformGeneric(int argIndex,int nElemsPerVector,GLMessage * glmsg,void * src)338 void fixup_glUniformGeneric(int argIndex, int nElemsPerVector, GLMessage *glmsg, void *src) {
339     GLMessage_DataType arg_count  = glmsg->args(1);
340     int n_vectors = arg_count.intvalue(0);
341     fixup_GenericFloatArray(argIndex, nElemsPerVector * n_vectors, glmsg, src);
342 }
343 
fixup_glUniformMatrixGeneric(int matrixSize,GLMessage * glmsg,void * pointersToFixup[])344 void fixup_glUniformMatrixGeneric(int matrixSize, GLMessage *glmsg, void *pointersToFixup[]) {
345     /* void glUniformMatrix?fv(GLint location, GLsizei count, GLboolean transpose,
346                                                                 const GLfloat* value) */
347     GLMessage_DataType arg_count  = glmsg->args(1);
348     int n_matrices = arg_count.intvalue(0);
349     fixup_glUniformGeneric(3, matrixSize * matrixSize * n_matrices, glmsg, pointersToFixup[0]);
350 }
351 
fixup_glGenGeneric(GLMessage * glmsg,void * pointersToFixup[])352 void fixup_glGenGeneric(GLMessage *glmsg, void *pointersToFixup[]) {
353     /* void glGen*(GLsizei n, GLuint * buffers); */
354     GLMessage_DataType arg_n  = glmsg->args(0);
355     GLsizei n = arg_n.intvalue(0);
356 
357     fixup_GenericIntArray(1, n, glmsg, pointersToFixup[0]);
358 }
359 
fixup_glDeleteGeneric(GLMessage * glmsg,void * pointersToFixup[])360 void fixup_glDeleteGeneric(GLMessage *glmsg, void *pointersToFixup[]) {
361     /* void glDelete*(GLsizei n, GLuint *buffers); */
362     GLMessage_DataType arg_n  = glmsg->args(0);
363     GLsizei n = arg_n.intvalue(0);
364 
365     fixup_GenericIntArray(1, n, glmsg, pointersToFixup[0]);
366 }
367 
fixup_glGetBooleanv(GLMessage * glmsg,void * pointersToFixup[])368 void fixup_glGetBooleanv(GLMessage *glmsg, void *pointersToFixup[]) {
369     /* void glGetBooleanv(GLenum pname, GLboolean *params); */
370     GLMessage_DataType *arg_params = glmsg->mutable_args(1);
371     GLboolean *src = (GLboolean*) pointersToFixup[0];
372 
373     arg_params->set_type(GLMessage::DataType::BOOL);
374     arg_params->set_isarray(true);
375     arg_params->clear_boolvalue();
376     arg_params->add_boolvalue(*src);
377 }
378 
fixup_glGetFloatv(GLMessage * glmsg,void * pointersToFixup[])379 void fixup_glGetFloatv(GLMessage *glmsg, void *pointersToFixup[]) {
380     /* void glGetFloatv(GLenum pname, GLfloat *params); */
381     GLMessage_DataType *arg_params = glmsg->mutable_args(1);
382     GLfloat *src = (GLfloat*) pointersToFixup[0];
383 
384     arg_params->set_type(GLMessage::DataType::FLOAT);
385     arg_params->set_isarray(true);
386     arg_params->clear_floatvalue();
387     arg_params->add_floatvalue(*src);
388 }
389 
fixup_glLinkProgram(GLMessage * glmsg)390 void fixup_glLinkProgram(GLMessage *glmsg) {
391     /* void glLinkProgram(GLuint program); */
392     GLuint program = glmsg->args(0).intvalue(0);
393 
394     /* We don't have to fixup this call, but as soon as a program is linked,
395        we obtain information about all active attributes and uniforms to
396        pass on to the debugger. Note that in order to pass this info to
397        the debugger, all we need to do is call the trace versions of the
398        necessary calls. */
399 
400     GLint n, maxNameLength;
401     GLchar *name;
402     GLint size;
403     GLenum type;
404 
405     // obtain info regarding active attributes
406     GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n);
407     GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength);
408 
409     name = (GLchar *) malloc(maxNameLength);
410     for (int i = 0; i < n; i++) {
411         GLTrace_glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name);
412     }
413     free(name);
414 
415     // obtain info regarding active uniforms
416     GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
417     GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
418 
419     name = (GLchar *) malloc(maxNameLength);
420     for (int i = 0; i < n; i++) {
421         GLTrace_glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name);
422     }
423     free(name);
424 }
425 
426 /** Given a glGetActive[Uniform|Attrib] call, obtain the location
427  *  of the variable of given name in the call.
428  */
getShaderVariableLocation(GLTraceContext * context,GLMessage * glmsg,GLchar * name)429 GLint getShaderVariableLocation(GLTraceContext *context, GLMessage *glmsg, GLchar *name) {
430     GLMessage_Function func = glmsg->function();
431     if (func != GLMessage::glGetActiveAttrib && func != GLMessage::glGetActiveUniform) {
432         return -1;
433     }
434 
435     int program = glmsg->args(0).intvalue(0);
436 
437     if (func == GLMessage::glGetActiveAttrib) {
438         return context->hooks->gl.glGetAttribLocation(program, name);
439     } else {
440         return context->hooks->gl.glGetUniformLocation(program, name);
441     }
442 }
443 
fixup_glGetActiveAttribOrUniform(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])444 void fixup_glGetActiveAttribOrUniform(GLTraceContext *context, GLMessage *glmsg,
445                                                                 void *pointersToFixup[]) {
446     /* void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
447                 GLsizei* length, GLint* size, GLenum* type, GLchar* name); */
448     /* void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
449                 GLsizei* length, GLint* size, GLenum* type, GLchar* name) */
450 
451     fixup_GenericIntArray(3, 1, glmsg, pointersToFixup[0]);     // length
452     fixup_GenericIntArray(4, 1, glmsg, pointersToFixup[1]);     // size
453     fixup_GenericEnumArray(5, 1, glmsg, pointersToFixup[2]);    // type
454     fixup_CStringPtr(6, glmsg, pointersToFixup[3]);             // name
455 
456     // The index argument in the glGetActive[Attrib|Uniform] functions
457     // does not correspond to the actual location index as used in
458     // glUniform*() or glVertexAttrib*() to actually upload the data.
459     // In order to make things simpler for the debugger, we also pass
460     // a hidden location argument that stores the actual location.
461     // append the location value to the end of the argument list
462     GLint location = getShaderVariableLocation(context, glmsg, (GLchar*)pointersToFixup[3]);
463     GLMessage_DataType *arg_location = glmsg->add_args();
464     arg_location->set_isarray(false);
465     arg_location->set_type(GLMessage::DataType::INT);
466     arg_location->add_intvalue(location);
467 }
468 
469 /** Copy @len bytes of data from @src into the @dataIndex'th argument of the message. */
addGlBufferData(GLMessage * glmsg,int dataIndex,GLvoid * src,GLsizeiptr len)470 void addGlBufferData(GLMessage *glmsg, int dataIndex, GLvoid *src, GLsizeiptr len) {
471     GLMessage_DataType *arg_datap = glmsg->mutable_args(dataIndex);
472     arg_datap->set_type(GLMessage::DataType::VOID);
473     arg_datap->set_isarray(true);
474     arg_datap->clear_intvalue();
475     arg_datap->add_rawbytes(src, len);
476 }
477 
fixup_glBufferData(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])478 void fixup_glBufferData(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
479     /* void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) */
480     GLsizeiptr size = glmsg->args(1).intvalue(0);
481     GLvoid *datap = (GLvoid *) pointersToFixup[0];
482 
483     // Save element array buffers for future use to fixup glVertexAttribPointers
484     // when a glDrawElements() call is performed.
485     GLenum target = glmsg->args(0).intvalue(0);
486     if (target == GL_ELEMENT_ARRAY_BUFFER) {
487         GLint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
488         context->bindBuffer(bufferId, datap, size);
489     }
490 
491     // add buffer data to the protobuf message
492     if (datap != NULL) {
493         addGlBufferData(glmsg, 2, datap, size);
494     }
495 }
496 
fixup_glBufferSubData(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])497 void fixup_glBufferSubData(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
498     /* void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) */
499     GLenum target = glmsg->args(0).intvalue(0);
500     GLintptr offset = glmsg->args(1).intvalue(0);
501     GLsizeiptr size = glmsg->args(2).intvalue(0);
502     GLvoid *datap = (GLvoid *) pointersToFixup[0];
503     if (target == GL_ELEMENT_ARRAY_BUFFER) {
504         GLint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
505         context->updateBufferSubData(bufferId, offset, datap, size);
506     }
507 
508     // add buffer data to the protobuf message
509     addGlBufferData(glmsg, 3, datap, size);
510 }
511 
512 /** Obtain the size of each vertex attribute. */
vertexAttribSize(GLenum type,GLsizei numComponents)513 int vertexAttribSize(GLenum type, GLsizei numComponents) {
514     int sizePerComponent;
515 
516     switch(type) {
517     case GL_BYTE:
518     case GL_UNSIGNED_BYTE:
519         sizePerComponent = 1;
520         break;
521     case GL_SHORT:
522     case GL_UNSIGNED_SHORT:
523         sizePerComponent = 2;
524         break;
525     case GL_FIXED:
526     case GL_FLOAT:
527     default:
528         sizePerComponent = 4;
529         break;
530     }
531 
532     return sizePerComponent * numComponents;
533 }
534 
535 /** Create and send a glVertexAttribPointerData trace message to the host. */
trace_glVertexAttribPointerData(GLTraceContext * context,GLuint indx,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const GLvoid * ptr,GLuint minIndex,GLuint maxIndex,nsecs_t startTime)536 void trace_glVertexAttribPointerData(GLTraceContext *context,
537                     GLuint indx, GLint size, GLenum type,
538                     GLboolean normalized, GLsizei stride, const GLvoid* ptr,
539                     GLuint minIndex, GLuint maxIndex, nsecs_t startTime) {
540     /* void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type,
541                     GLboolean normalized, GLsizei stride, const GLvoid* ptr,
542                     int minIndex, int maxIndex) */
543     GLMessage glmsg;
544     GLTraceContext *glContext = context;
545 
546     glmsg.set_function(GLMessage::glVertexAttribPointerData);
547 
548     // copy argument indx
549     GLMessage_DataType *arg_indx = glmsg.add_args();
550     arg_indx->set_isarray(false);
551     arg_indx->set_type(GLMessage::DataType::INT);
552     arg_indx->add_intvalue(indx);
553 
554     // copy argument size
555     GLMessage_DataType *arg_size = glmsg.add_args();
556     arg_size->set_isarray(false);
557     arg_size->set_type(GLMessage::DataType::INT);
558     arg_size->add_intvalue(size);
559 
560     // copy argument type
561     GLMessage_DataType *arg_type = glmsg.add_args();
562     arg_type->set_isarray(false);
563     arg_type->set_type(GLMessage::DataType::ENUM);
564     arg_type->add_intvalue((int)type);
565 
566     // copy argument normalized
567     GLMessage_DataType *arg_normalized = glmsg.add_args();
568     arg_normalized->set_isarray(false);
569     arg_normalized->set_type(GLMessage::DataType::BOOL);
570     arg_normalized->add_boolvalue(normalized);
571 
572     // copy argument stride
573     GLMessage_DataType *arg_stride = glmsg.add_args();
574     arg_stride->set_isarray(false);
575     arg_stride->set_type(GLMessage::DataType::INT);
576     arg_stride->add_intvalue(stride);
577 
578     // copy argument ptr
579     GLMessage_DataType *arg_ptr = glmsg.add_args();
580     arg_ptr->set_isarray(true);
581     arg_ptr->set_type(GLMessage::DataType::BYTE);
582     int perVertexSize = vertexAttribSize(type, size);
583     GLchar *p = (GLchar*) ptr;
584     std::string data;
585     for (GLuint i = minIndex; i < maxIndex; i++) {
586         data.append(p, perVertexSize);
587         p += stride == 0 ? perVertexSize : stride;
588     }
589     arg_ptr->add_rawbytes(data);
590 
591     // copy argument min index
592     GLMessage_DataType *arg_min = glmsg.add_args();
593     arg_min->set_isarray(false);
594     arg_min->set_type(GLMessage::DataType::INT);
595     arg_min->add_intvalue(minIndex);
596 
597     // copy argument max index
598     GLMessage_DataType *arg_max = glmsg.add_args();
599     arg_max->set_isarray(false);
600     arg_max->set_type(GLMessage::DataType::INT);
601     arg_max->add_intvalue(maxIndex);
602 
603     glmsg.set_context_id(context->getId());
604     glmsg.set_start_time(startTime);
605     glmsg.set_threadtime(0);
606     glmsg.set_duration(0);
607 
608     context->traceGLMessage(&glmsg);
609 }
610 
findMinAndMaxIndices(GLvoid * indices,GLsizei count,GLenum type,GLuint * minIndex,GLuint * maxIndex)611 void findMinAndMaxIndices(GLvoid *indices, GLsizei count, GLenum type,
612                             GLuint *minIndex, GLuint *maxIndex) {
613     GLuint index;
614     *minIndex = UINT_MAX;
615     *maxIndex = 0;
616 
617     if (indices == NULL) {
618         return;
619     }
620 
621     for (GLsizei i = 0; i < count; i++) {
622         if (type == GL_UNSIGNED_BYTE) {
623             index = *((GLubyte*) indices + i);
624         } else {
625             index = *((GLushort*) indices + i);
626         }
627 
628         if (index < *minIndex) *minIndex = index;
629         if (index > *maxIndex) *maxIndex = index;
630     }
631 }
632 
trace_VertexAttribPointerData(GLTraceContext * context,GLuint minIndex,GLuint maxIndex,nsecs_t time)633 void trace_VertexAttribPointerData(GLTraceContext *context,
634                             GLuint minIndex, GLuint maxIndex, nsecs_t time) {
635     GLuint maxAttribs = glGetInteger(context, GL_MAX_VERTEX_ATTRIBS);
636     for (GLuint index = 0; index < maxAttribs; index++) {
637         if (!glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_ENABLED)) {
638             // vertex array disabled
639             continue;
640         }
641 
642         if (glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)) {
643             // vbo
644             continue;
645         }
646 
647         GLint size = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_SIZE);
648         GLenum type = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_TYPE);
649         GLboolean norm = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED);
650         GLsizei stride = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_STRIDE);
651         GLvoid* ptr;
652         context->hooks->gl.glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr);
653 
654         trace_glVertexAttribPointerData(context,
655                     index, size, type, norm, stride, ptr,
656                     minIndex, maxIndex, time);
657     }
658 }
659 
trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext * context,GLMessage * glmsg)660 void trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext *context, GLMessage *glmsg) {
661     if (context->getVersion() == egl_connection_t::GLESv1_INDEX) {
662         // only supported for GLES2 and above
663         return;
664     }
665 
666     /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
667     GLsizei count = glmsg->args(2).intvalue(0);
668 
669     // Vertex attrib pointer data patchup calls should appear as if
670     // they occurred right before the draw call.
671     nsecs_t time = glmsg->start_time() - 1;
672 
673     trace_VertexAttribPointerData(context, 0, count, time);
674 }
675 
trace_VertexAttribPointerDataForGlDrawElements(GLTraceContext * context,GLMessage * glmsg,GLvoid * indices)676 void trace_VertexAttribPointerDataForGlDrawElements(GLTraceContext *context, GLMessage *glmsg,
677                             GLvoid *indices) {
678     if (context->getVersion() == egl_connection_t::GLESv1_INDEX) {
679         // only supported for GLES2 and above
680         return;
681     }
682 
683     /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
684     GLsizei count = glmsg->args(1).intvalue(0);
685     GLenum type = glmsg->args(2).intvalue(0);
686     GLuint index;
687 
688     GLuint minIndex, maxIndex;
689 
690     // The index buffer is either passed in as an argument to the glDrawElements() call,
691     // or it is stored in the current GL_ELEMENT_ARRAY_BUFFER.
692     GLvoid *indexBuffer;
693     if (isUsingElementArrayBuffers(context)) {
694         GLsizeiptr eaBufferSize;
695         GLuint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
696         context->getBuffer(bufferId, &indexBuffer, &eaBufferSize);
697     } else {
698         indexBuffer = indices;
699     }
700 
701     // Rather than sending vertex attribute data that corresponds to the indices
702     // being drawn, we send the vertex attribute data for the entire range of
703     // indices being drawn, including the ones not drawn. The min & max indices
704     // provide the range of indices being drawn.
705     findMinAndMaxIndices(indexBuffer, count, type, &minIndex, &maxIndex);
706 
707     // Vertex attrib pointer data patchup calls should appear as if
708     // they occurred right before the draw call.
709     nsecs_t time = glmsg->start_time() - 1;
710 
711     trace_VertexAttribPointerData(context, minIndex, maxIndex + 1, time);
712 }
713 
fixup_glDrawArrays(GLTraceContext * context,GLMessage * glmsg)714 void fixup_glDrawArrays(GLTraceContext *context, GLMessage *glmsg) {
715     // Trace all vertex attribute data stored in client space.
716     trace_VertexAttribPointerDataForGlDrawArrays(context, glmsg);
717 
718     // Attach the FB if requested
719     if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
720         fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
721     }
722 }
723 
fixup_glDrawElements(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])724 void fixup_glDrawElements(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
725     /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
726     GLvoid *indices = pointersToFixup[0];
727     GLenum type = glmsg->args(2).intvalue(0);
728     GLsizei count = glmsg->args(1).intvalue(0);
729     GLuint index;
730 
731     // Trace all vertex attribute data stored in client space.
732     trace_VertexAttribPointerDataForGlDrawElements(context, glmsg, indices);
733 
734     // Fixup indices argument
735     if (!isUsingElementArrayBuffers(context)) {
736         GLMessage_DataType *arg_indices = glmsg->mutable_args(3);
737         arg_indices->set_isarray(true);
738         arg_indices->clear_intvalue();
739         arg_indices->set_type(GLMessage::DataType::INT);
740         for (GLsizei i = 0; i < count; i++) {
741             if (type == GL_UNSIGNED_BYTE) {
742                 index = *((GLubyte*) indices + i);
743             } else {
744                 index = *((GLushort*) indices + i);
745             }
746             arg_indices->add_intvalue(index);
747         }
748     }
749 
750     // Attach the FB if requested
751     if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
752         fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
753     }
754 }
755 
fixupGLMessage(GLTraceContext * context,nsecs_t wallStart,nsecs_t wallEnd,nsecs_t threadStart,nsecs_t threadEnd,GLMessage * glmsg,void * pointersToFixup[])756 void fixupGLMessage(GLTraceContext *context, nsecs_t wallStart, nsecs_t wallEnd,
757                                              nsecs_t threadStart, nsecs_t threadEnd,
758                                              GLMessage *glmsg, void *pointersToFixup[]) {
759     // for all messages, set the current context id
760     glmsg->set_context_id(context->getId());
761 
762     // set start time and duration
763     glmsg->set_start_time(wallStart);
764     glmsg->set_duration((unsigned)(wallEnd - wallStart));
765     glmsg->set_threadtime((unsigned)(threadEnd - threadStart));
766 
767     // do any custom message dependent processing
768     switch (glmsg->function()) {
769     case GLMessage::glDeleteBuffers:      /* glDeleteBuffers(GLsizei n, GLuint *buffers); */
770     case GLMessage::glDeleteFramebuffers: /* glDeleteFramebuffers(GLsizei n, GLuint *buffers); */
771     case GLMessage::glDeleteRenderbuffers:/* glDeleteRenderbuffers(GLsizei n, GLuint *buffers); */
772     case GLMessage::glDeleteTextures:     /* glDeleteTextures(GLsizei n, GLuint *textures); */
773         fixup_glDeleteGeneric(glmsg, pointersToFixup);
774         break;
775     case GLMessage::glGenBuffers:        /* void glGenBuffers(GLsizei n, GLuint *buffers); */
776     case GLMessage::glGenFramebuffers:   /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
777     case GLMessage::glGenRenderbuffers:  /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
778     case GLMessage::glGenTextures:       /* void glGenTextures(GLsizei n, GLuint *textures); */
779         fixup_glGenGeneric(glmsg, pointersToFixup);
780         break;
781     case GLMessage::glLinkProgram:       /* void glLinkProgram(GLuint program); */
782         fixup_glLinkProgram(glmsg);
783         break;
784     case GLMessage::glGetActiveAttrib:
785         fixup_glGetActiveAttribOrUniform(context, glmsg, pointersToFixup);
786         break;
787     case GLMessage::glGetActiveUniform:
788         fixup_glGetActiveAttribOrUniform(context, glmsg, pointersToFixup);
789         break;
790     case GLMessage::glBindAttribLocation:
791         /* void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); */
792         fixup_CStringPtr(2, glmsg, pointersToFixup[0]);
793         break;
794     case GLMessage::glGetAttribLocation:
795     case GLMessage::glGetUniformLocation:
796         /* int glGetAttribLocation(GLuint program, const GLchar* name) */
797         /* int glGetUniformLocation(GLuint program, const GLchar* name) */
798         fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
799         break;
800     case GLMessage::glGetBooleanv:
801         fixup_glGetBooleanv(glmsg, pointersToFixup);
802         break;
803     case GLMessage::glGetFloatv:
804         fixup_glGetFloatv(glmsg, pointersToFixup);
805         break;
806     case GLMessage::glGetIntegerv:        /* void glGetIntegerv(GLenum pname, GLint *params); */
807         fixup_GenericIntArray(1, 1, glmsg, pointersToFixup[0]);
808         break;
809     case GLMessage::glGetProgramiv:
810     case GLMessage::glGetRenderbufferParameteriv:
811     case GLMessage::glGetShaderiv:
812         /* void glGetProgramiv(GLuint program, GLenum pname, GLint* params) */
813         /* void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) */
814         /* void glGetShaderiv(GLuint shader, GLenum pname, GLint* params) */
815         fixup_GenericIntArray(2, 1, glmsg, pointersToFixup[0]);
816         break;
817     case GLMessage::glGetString:
818         fixup_glGetString(glmsg, pointersToFixup);
819         break;
820     case GLMessage::glTexImage2D:
821         if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
822             fixup_glTexImage2D(context, glmsg, pointersToFixup);
823         }
824         break;
825     case GLMessage::glTexSubImage2D:
826         if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
827             fixup_glTexSubImage2D(context, glmsg, pointersToFixup);
828         }
829         break;
830     case GLMessage::glCompressedTexImage2D:
831         if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
832             fixup_glCompressedTexImage2D(context, glmsg, pointersToFixup);
833         }
834         break;
835     case GLMessage::glCompressedTexSubImage2D:
836         if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
837             fixup_glCompressedTexSubImage2D(context, glmsg, pointersToFixup);
838         }
839         break;
840     case GLMessage::glShaderSource:
841         fixup_glShaderSource(glmsg, pointersToFixup);
842         break;
843     case GLMessage::glUniform1iv:
844         /* void glUniform1iv(GLint location, GLsizei count, const GLint *value); */
845         fixup_glUniformGenericInteger(2, 1, glmsg, pointersToFixup);
846         break;
847     case GLMessage::glUniform2iv:
848         /* void glUniform2iv(GLint location, GLsizei count, const GLint *value); */
849         fixup_glUniformGenericInteger(2, 2, glmsg, pointersToFixup);
850         break;
851     case GLMessage::glUniform3iv:
852         /* void glUniform3iv(GLint location, GLsizei count, const GLint *value); */
853         fixup_glUniformGenericInteger(2, 3, glmsg, pointersToFixup);
854         break;
855     case GLMessage::glUniform4iv:
856         /* void glUniform4iv(GLint location, GLsizei count, const GLint *value); */
857         fixup_glUniformGenericInteger(2, 4, glmsg, pointersToFixup);
858         break;
859     case GLMessage::glUniform1fv:
860         /* void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); */
861         fixup_glUniformGeneric(2, 1, glmsg, pointersToFixup[0]);
862         break;
863     case GLMessage::glUniform2fv:
864         /* void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); */
865         fixup_glUniformGeneric(2, 2, glmsg, pointersToFixup[0]);
866         break;
867     case GLMessage::glUniform3fv:
868         /* void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); */
869         fixup_glUniformGeneric(2, 3, glmsg, pointersToFixup[0]);
870         break;
871     case GLMessage::glUniform4fv:
872         /* void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); */
873         fixup_glUniformGeneric(2, 4, glmsg, pointersToFixup[0]);
874         break;
875     case GLMessage::glUniformMatrix2fv:
876         /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
877                                                                     const GLfloat* value) */
878         fixup_glUniformMatrixGeneric(2, glmsg, pointersToFixup);
879         break;
880     case GLMessage::glUniformMatrix3fv:
881         /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
882                                                                     const GLfloat* value) */
883         fixup_glUniformMatrixGeneric(3, glmsg, pointersToFixup);
884         break;
885     case GLMessage::glUniformMatrix4fv:
886         /* void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
887                                                                     const GLfloat* value) */
888         fixup_glUniformMatrixGeneric(4, glmsg, pointersToFixup);
889         break;
890     case GLMessage::glBufferData:
891         /* void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) */
892         fixup_glBufferData(context, glmsg, pointersToFixup);
893         break;
894     case GLMessage::glBufferSubData:
895         /* void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) */
896         fixup_glBufferSubData(context, glmsg, pointersToFixup);
897         break;
898     case GLMessage::glDrawArrays:
899         /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
900         fixup_glDrawArrays(context, glmsg);
901         break;
902     case GLMessage::glDrawElements:
903         /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
904         fixup_glDrawElements(context, glmsg, pointersToFixup);
905         break;
906     case GLMessage::glPushGroupMarkerEXT:
907         /* void PushGroupMarkerEXT(sizei length, const char *marker); */
908         fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
909         break;
910     case GLMessage::glInsertEventMarkerEXT:
911         /* void InsertEventMarkerEXT(sizei length, const char *marker); */
912         fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
913         break;
914     default:
915         break;
916     }
917 }
918 
919 };
920 };
921