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