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