Home | History | Annotate | Download | only in src
      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 
     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 
     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 
     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 
    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 */
    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 
    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 */
    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. */
    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 
    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 
    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 
    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         stringpp++;
    243         lengthp++;
    244     }
    245 
    246     arg_strpp->add_charvalue(src);
    247 }
    248 
    249 void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg,
    250                                                                     void *pointersToFixup[]) {
    251     /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */
    252     fixup_GenericIntArray(argIndex, nIntegers, glmsg, pointersToFixup[0]);
    253 }
    254 
    255 void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg, void *src) {
    256     fixup_GenericFloatArray(argIndex, nFloats, glmsg, src);
    257 }
    258 
    259 void fixup_glUniformMatrixGeneric(int matrixSize, GLMessage *glmsg, void *pointersToFixup[]) {
    260     /* void glUniformMatrix?fv(GLint location, GLsizei count, GLboolean transpose,
    261                                                                 const GLfloat* value) */
    262     GLMessage_DataType arg_count  = glmsg->args(1);
    263     int n_matrices = arg_count.intvalue(0);
    264     fixup_glUniformGeneric(3, matrixSize * matrixSize * n_matrices, glmsg, pointersToFixup[0]);
    265 }
    266 
    267 void fixup_glGenGeneric(GLMessage *glmsg, void *pointersToFixup[]) {
    268     /* void glGen*(GLsizei n, GLuint * buffers); */
    269     GLMessage_DataType arg_n  = glmsg->args(0);
    270     GLsizei n = arg_n.intvalue(0);
    271 
    272     fixup_GenericIntArray(1, n, glmsg, pointersToFixup[0]);
    273 }
    274 
    275 void fixup_glDeleteGeneric(GLMessage *glmsg, void *pointersToFixup[]) {
    276     /* void glDelete*(GLsizei n, GLuint *buffers); */
    277     GLMessage_DataType arg_n  = glmsg->args(0);
    278     GLsizei n = arg_n.intvalue(0);
    279 
    280     fixup_GenericIntArray(1, n, glmsg, pointersToFixup[0]);
    281 }
    282 
    283 void fixup_glGetBooleanv(GLMessage *glmsg, void *pointersToFixup[]) {
    284     /* void glGetBooleanv(GLenum pname, GLboolean *params); */
    285     GLMessage_DataType *arg_params = glmsg->mutable_args(1);
    286     GLboolean *src = (GLboolean*) pointersToFixup[0];
    287 
    288     arg_params->set_type(GLMessage::DataType::BOOL);
    289     arg_params->set_isarray(true);
    290     arg_params->clear_boolvalue();
    291     arg_params->add_boolvalue(*src);
    292 }
    293 
    294 void fixup_glGetFloatv(GLMessage *glmsg, void *pointersToFixup[]) {
    295     /* void glGetFloatv(GLenum pname, GLfloat *params); */
    296     GLMessage_DataType *arg_params = glmsg->mutable_args(1);
    297     GLfloat *src = (GLfloat*) pointersToFixup[0];
    298 
    299     arg_params->set_type(GLMessage::DataType::FLOAT);
    300     arg_params->set_isarray(true);
    301     arg_params->clear_floatvalue();
    302     arg_params->add_floatvalue(*src);
    303 }
    304 
    305 void fixup_glLinkProgram(GLMessage *glmsg) {
    306     /* void glLinkProgram(GLuint program); */
    307     GLuint program = glmsg->args(0).intvalue(0);
    308 
    309     /* We don't have to fixup this call, but as soon as a program is linked,
    310        we obtain information about all active attributes and uniforms to
    311        pass on to the debugger. Note that in order to pass this info to
    312        the debugger, all we need to do is call the trace versions of the
    313        necessary calls. */
    314 
    315     GLint n, maxNameLength;
    316     GLchar *name;
    317     GLint size;
    318     GLenum type;
    319 
    320     // obtain info regarding active attributes
    321     GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n);
    322     GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength);
    323 
    324     name = (GLchar *) malloc(maxNameLength);
    325     for (int i = 0; i < n; i++) {
    326         GLTrace_glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name);
    327     }
    328     free(name);
    329 
    330     // obtain info regarding active uniforms
    331     GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
    332     GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
    333 
    334     name = (GLchar *) malloc(maxNameLength);
    335     for (int i = 0; i < n; i++) {
    336         GLTrace_glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name);
    337     }
    338     free(name);
    339 }
    340 
    341 /** Given a glGetActive[Uniform|Attrib] call, obtain the location
    342  *  of the variable of given name in the call.
    343  */
    344 int getShaderVariableLocation(GLTraceContext *context, GLMessage *glmsg, GLchar *name) {
    345     GLMessage_Function func = glmsg->function();
    346     if (func != GLMessage::glGetActiveAttrib && func != GLMessage::glGetActiveUniform) {
    347         return -1;
    348     }
    349 
    350     int program = glmsg->args(0).intvalue(0);
    351 
    352     if (func == GLMessage::glGetActiveAttrib) {
    353         return context->hooks->gl.glGetAttribLocation(program, name);
    354     } else {
    355         return context->hooks->gl.glGetUniformLocation(program, name);
    356     }
    357 }
    358 
    359 void fixup_glGetActiveAttribOrUniform(GLTraceContext *context, GLMessage *glmsg,
    360                                                                 void *pointersToFixup[]) {
    361     /* void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
    362                 GLsizei* length, GLint* size, GLenum* type, GLchar* name); */
    363     /* void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
    364                 GLsizei* length, GLint* size, GLenum* type, GLchar* name) */
    365 
    366     fixup_GenericIntArray(3, 1, glmsg, pointersToFixup[0]);     // length
    367     fixup_GenericIntArray(4, 1, glmsg, pointersToFixup[1]);     // size
    368     fixup_GenericEnumArray(5, 1, glmsg, pointersToFixup[2]);    // type
    369     fixup_CStringPtr(6, glmsg, pointersToFixup[3]);             // name
    370 
    371     // The index argument in the glGetActive[Attrib|Uniform] functions
    372     // does not correspond to the actual location index as used in
    373     // glUniform*() or glVertexAttrib*() to actually upload the data.
    374     // In order to make things simpler for the debugger, we also pass
    375     // a hidden location argument that stores the actual location.
    376     // append the location value to the end of the argument list
    377     int location = getShaderVariableLocation(context, glmsg, (GLchar*)pointersToFixup[3]);
    378     GLMessage_DataType *arg_location = glmsg->add_args();
    379     arg_location->set_isarray(false);
    380     arg_location->set_type(GLMessage::DataType::INT);
    381     arg_location->add_intvalue(location);
    382 }
    383 
    384 GLint glGetInteger(GLTraceContext *context, GLenum param) {
    385     GLint x;
    386     context->hooks->gl.glGetIntegerv(param, &x);
    387     return x;
    388 }
    389 
    390 GLint glGetVertexAttrib(GLTraceContext *context, GLuint index, GLenum pname) {
    391     GLint x;
    392     context->hooks->gl.glGetVertexAttribiv(index, pname, &x);
    393     return x;
    394 }
    395 
    396 bool isUsingArrayBuffers(GLTraceContext *context) {
    397     return glGetInteger(context, GL_ARRAY_BUFFER_BINDING) != 0;
    398 }
    399 
    400 bool isUsingElementArrayBuffers(GLTraceContext *context) {
    401     return glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING) != 0;
    402 }
    403 
    404 /** Copy @len bytes of data from @src into the @dataIndex'th argument of the message. */
    405 void addGlBufferData(GLMessage *glmsg, int dataIndex, GLvoid *src, GLsizeiptr len) {
    406     GLMessage_DataType *arg_datap = glmsg->mutable_args(dataIndex);
    407     arg_datap->set_type(GLMessage::DataType::VOID);
    408     arg_datap->set_isarray(true);
    409     arg_datap->clear_intvalue();
    410     arg_datap->add_rawbytes(src, len);
    411 }
    412 
    413 void fixup_glBufferData(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
    414     /* void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) */
    415     GLsizeiptr size = glmsg->args(1).intvalue(0);
    416     GLvoid *datap = (GLvoid *) pointersToFixup[0];
    417 
    418     // Save element array buffers for future use to fixup glVertexAttribPointers
    419     // when a glDrawElements() call is performed.
    420     GLenum target = glmsg->args(0).intvalue(0);
    421     if (target == GL_ELEMENT_ARRAY_BUFFER) {
    422         GLint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
    423         context->bindBuffer(bufferId, datap, size);
    424     }
    425 
    426     // add buffer data to the protobuf message
    427     if (datap != NULL) {
    428         addGlBufferData(glmsg, 2, datap, size);
    429     }
    430 }
    431 
    432 void fixup_glBufferSubData(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
    433     /* void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) */
    434     GLenum target = glmsg->args(0).intvalue(0);
    435     GLintptr offset = glmsg->args(1).intvalue(0);
    436     GLsizeiptr size = glmsg->args(2).intvalue(0);
    437     GLvoid *datap = (GLvoid *) pointersToFixup[0];
    438     if (target == GL_ELEMENT_ARRAY_BUFFER) {
    439         GLint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
    440         context->updateBufferSubData(bufferId, offset, datap, size);
    441     }
    442 
    443     // add buffer data to the protobuf message
    444     addGlBufferData(glmsg, 3, datap, size);
    445 }
    446 
    447 /** Obtain the size of each vertex attribute. */
    448 int vertexAttribSize(GLenum type, GLsizei numComponents) {
    449     int sizePerComponent;
    450 
    451     switch(type) {
    452     case GL_BYTE:
    453     case GL_UNSIGNED_BYTE:
    454         sizePerComponent = 1;
    455         break;
    456     case GL_SHORT:
    457     case GL_UNSIGNED_SHORT:
    458         sizePerComponent = 2;
    459         break;
    460     case GL_FIXED:
    461     case GL_FLOAT:
    462     default:
    463         sizePerComponent = 4;
    464         break;
    465     }
    466 
    467     return sizePerComponent * numComponents;
    468 }
    469 
    470 /** Create and send a glVertexAttribPointerData trace message to the host. */
    471 void trace_glVertexAttribPointerData(GLTraceContext *context,
    472                     GLuint indx, GLint size, GLenum type,
    473                     GLboolean normalized, GLsizei stride, const GLvoid* ptr,
    474                     GLuint minIndex, GLuint maxIndex, nsecs_t startTime) {
    475     /* void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type,
    476                     GLboolean normalized, GLsizei stride, const GLvoid* ptr,
    477                     int minIndex, int maxIndex) */
    478     GLMessage glmsg;
    479     GLTraceContext *glContext = context;
    480 
    481     glmsg.set_function(GLMessage::glVertexAttribPointerData);
    482 
    483     // copy argument indx
    484     GLMessage_DataType *arg_indx = glmsg.add_args();
    485     arg_indx->set_isarray(false);
    486     arg_indx->set_type(GLMessage::DataType::INT);
    487     arg_indx->add_intvalue(indx);
    488 
    489     // copy argument size
    490     GLMessage_DataType *arg_size = glmsg.add_args();
    491     arg_size->set_isarray(false);
    492     arg_size->set_type(GLMessage::DataType::INT);
    493     arg_size->add_intvalue(size);
    494 
    495     // copy argument type
    496     GLMessage_DataType *arg_type = glmsg.add_args();
    497     arg_type->set_isarray(false);
    498     arg_type->set_type(GLMessage::DataType::ENUM);
    499     arg_type->add_intvalue((int)type);
    500 
    501     // copy argument normalized
    502     GLMessage_DataType *arg_normalized = glmsg.add_args();
    503     arg_normalized->set_isarray(false);
    504     arg_normalized->set_type(GLMessage::DataType::BOOL);
    505     arg_normalized->add_boolvalue(normalized);
    506 
    507     // copy argument stride
    508     GLMessage_DataType *arg_stride = glmsg.add_args();
    509     arg_stride->set_isarray(false);
    510     arg_stride->set_type(GLMessage::DataType::INT);
    511     arg_stride->add_intvalue(stride);
    512 
    513     // copy argument ptr
    514     GLMessage_DataType *arg_ptr = glmsg.add_args();
    515     arg_ptr->set_isarray(true);
    516     arg_ptr->set_type(GLMessage::DataType::BYTE);
    517     int perVertexSize = vertexAttribSize(type, size);
    518     GLchar *p = (GLchar*) ptr;
    519     std::string data;
    520     for (GLuint i = minIndex; i < maxIndex; i++) {
    521         data.append(p, perVertexSize);
    522         p += stride == 0 ? perVertexSize : stride;
    523     }
    524     arg_ptr->add_rawbytes(data);
    525 
    526     // copy argument min index
    527     GLMessage_DataType *arg_min = glmsg.add_args();
    528     arg_min->set_isarray(false);
    529     arg_min->set_type(GLMessage::DataType::INT);
    530     arg_min->add_intvalue(minIndex);
    531 
    532     // copy argument max index
    533     GLMessage_DataType *arg_max = glmsg.add_args();
    534     arg_max->set_isarray(false);
    535     arg_max->set_type(GLMessage::DataType::INT);
    536     arg_max->add_intvalue(maxIndex);
    537 
    538     glmsg.set_context_id(context->getId());
    539     glmsg.set_start_time(startTime);
    540     glmsg.set_threadtime(0);
    541     glmsg.set_duration(0);
    542 
    543     context->traceGLMessage(&glmsg);
    544 }
    545 
    546 void findMinAndMaxIndices(GLvoid *indices, GLsizei count, GLenum type,
    547                             GLuint *minIndex, GLuint *maxIndex) {
    548     GLuint index;
    549     *minIndex = UINT_MAX;
    550     *maxIndex = 0;
    551 
    552     if (indices == NULL) {
    553         return;
    554     }
    555 
    556     for (GLsizei i = 0; i < count; i++) {
    557         if (type == GL_UNSIGNED_BYTE) {
    558             index = *((GLubyte*) indices + i);
    559         } else {
    560             index = *((GLushort*) indices + i);
    561         }
    562 
    563         if (index < *minIndex) *minIndex = index;
    564         if (index > *maxIndex) *maxIndex = index;
    565     }
    566 }
    567 
    568 void trace_VertexAttribPointerData(GLTraceContext *context,
    569                             GLuint minIndex, GLuint maxIndex, nsecs_t time) {
    570     GLuint maxAttribs = glGetInteger(context, GL_MAX_VERTEX_ATTRIBS);
    571     for (GLuint index = 0; index < maxAttribs; index++) {
    572         if (!glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_ENABLED)) {
    573             // vertex array disabled
    574             continue;
    575         }
    576 
    577         if (glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)) {
    578             // vbo
    579             continue;
    580         }
    581 
    582         GLint size = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_SIZE);
    583         GLenum type = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_TYPE);
    584         GLboolean norm = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED);
    585         GLsizei stride = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_STRIDE);
    586         GLvoid* ptr;
    587         context->hooks->gl.glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr);
    588 
    589         trace_glVertexAttribPointerData(context,
    590                     index, size, type, norm, stride, ptr,
    591                     minIndex, maxIndex, time);
    592     }
    593 }
    594 
    595 void trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext *context, GLMessage *glmsg) {
    596     if (context->getVersion() == egl_connection_t::GLESv1_INDEX) {
    597         // only supported for GLES2 and above
    598         return;
    599     }
    600 
    601     /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
    602     GLsizei count = glmsg->args(2).intvalue(0);
    603 
    604     // Vertex attrib pointer data patchup calls should appear as if
    605     // they occurred right before the draw call.
    606     nsecs_t time = glmsg->start_time() - 1;
    607 
    608     trace_VertexAttribPointerData(context, 0, count, time);
    609 }
    610 
    611 void trace_VertexAttribPointerDataForGlDrawElements(GLTraceContext *context, GLMessage *glmsg,
    612                             GLvoid *indices) {
    613     if (context->getVersion() == egl_connection_t::GLESv1_INDEX) {
    614         // only supported for GLES2 and above
    615         return;
    616     }
    617 
    618     /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
    619     GLsizei count = glmsg->args(1).intvalue(0);
    620     GLenum type = glmsg->args(2).intvalue(0);
    621     GLuint index;
    622 
    623     GLuint minIndex, maxIndex;
    624 
    625     // The index buffer is either passed in as an argument to the glDrawElements() call,
    626     // or it is stored in the current GL_ELEMENT_ARRAY_BUFFER.
    627     GLvoid *indexBuffer;
    628     if (isUsingElementArrayBuffers(context)) {
    629         GLsizeiptr eaBufferSize;
    630         GLuint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
    631         context->getBuffer(bufferId, &indexBuffer, &eaBufferSize);
    632     } else {
    633         indexBuffer = indices;
    634     }
    635 
    636     // Rather than sending vertex attribute data that corresponds to the indices
    637     // being drawn, we send the vertex attribute data for the entire range of
    638     // indices being drawn, including the ones not drawn. The min & max indices
    639     // provide the range of indices being drawn.
    640     findMinAndMaxIndices(indexBuffer, count, type, &minIndex, &maxIndex);
    641 
    642     // Vertex attrib pointer data patchup calls should appear as if
    643     // they occurred right before the draw call.
    644     nsecs_t time = glmsg->start_time() - 1;
    645 
    646     trace_VertexAttribPointerData(context, minIndex, maxIndex + 1, time);
    647 }
    648 
    649 void fixup_glDrawArrays(GLTraceContext *context, GLMessage *glmsg) {
    650     // Trace all vertex attribute data stored in client space.
    651     trace_VertexAttribPointerDataForGlDrawArrays(context, glmsg);
    652 
    653     // Attach the FB if requested
    654     if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
    655         fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
    656     }
    657 }
    658 
    659 void fixup_glDrawElements(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
    660     /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
    661     GLvoid *indices = pointersToFixup[0];
    662     GLenum type = glmsg->args(2).intvalue(0);
    663     GLsizei count = glmsg->args(1).intvalue(0);
    664     GLuint index;
    665 
    666     // Trace all vertex attribute data stored in client space.
    667     trace_VertexAttribPointerDataForGlDrawElements(context, glmsg, indices);
    668 
    669     // Fixup indices argument
    670     if (!isUsingElementArrayBuffers(context)) {
    671         GLMessage_DataType *arg_indices = glmsg->mutable_args(3);
    672         arg_indices->set_isarray(true);
    673         arg_indices->clear_intvalue();
    674         arg_indices->set_type(GLMessage::DataType::INT);
    675         for (GLsizei i = 0; i < count; i++) {
    676             if (type == GL_UNSIGNED_BYTE) {
    677                 index = *((GLubyte*) indices + i);
    678             } else {
    679                 index = *((GLushort*) indices + i);
    680             }
    681             arg_indices->add_intvalue(index);
    682         }
    683     }
    684 
    685     // Attach the FB if requested
    686     if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
    687         fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
    688     }
    689 }
    690 
    691 void fixupGLMessage(GLTraceContext *context, nsecs_t wallStart, nsecs_t wallEnd,
    692                                              nsecs_t threadStart, nsecs_t threadEnd,
    693                                              GLMessage *glmsg, void *pointersToFixup[]) {
    694     // for all messages, set the current context id
    695     glmsg->set_context_id(context->getId());
    696 
    697     // set start time and duration
    698     glmsg->set_start_time(wallStart);
    699     glmsg->set_duration((unsigned)(wallEnd - wallStart));
    700     glmsg->set_threadtime((unsigned)(threadEnd - threadStart));
    701 
    702     // do any custom message dependent processing
    703     switch (glmsg->function()) {
    704     case GLMessage::glDeleteBuffers:      /* glDeleteBuffers(GLsizei n, GLuint *buffers); */
    705     case GLMessage::glDeleteFramebuffers: /* glDeleteFramebuffers(GLsizei n, GLuint *buffers); */
    706     case GLMessage::glDeleteRenderbuffers:/* glDeleteRenderbuffers(GLsizei n, GLuint *buffers); */
    707     case GLMessage::glDeleteTextures:     /* glDeleteTextures(GLsizei n, GLuint *textures); */
    708         fixup_glDeleteGeneric(glmsg, pointersToFixup);
    709         break;
    710     case GLMessage::glGenBuffers:        /* void glGenBuffers(GLsizei n, GLuint *buffers); */
    711     case GLMessage::glGenFramebuffers:   /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
    712     case GLMessage::glGenRenderbuffers:  /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
    713     case GLMessage::glGenTextures:       /* void glGenTextures(GLsizei n, GLuint *textures); */
    714         fixup_glGenGeneric(glmsg, pointersToFixup);
    715         break;
    716     case GLMessage::glLinkProgram:       /* void glLinkProgram(GLuint program); */
    717         fixup_glLinkProgram(glmsg);
    718         break;
    719     case GLMessage::glGetActiveAttrib:
    720         fixup_glGetActiveAttribOrUniform(context, glmsg, pointersToFixup);
    721         break;
    722     case GLMessage::glGetActiveUniform:
    723         fixup_glGetActiveAttribOrUniform(context, glmsg, pointersToFixup);
    724         break;
    725     case GLMessage::glBindAttribLocation:
    726         /* void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); */
    727         fixup_CStringPtr(2, glmsg, pointersToFixup[0]);
    728         break;
    729     case GLMessage::glGetAttribLocation:
    730     case GLMessage::glGetUniformLocation:
    731         /* int glGetAttribLocation(GLuint program, const GLchar* name) */
    732         /* int glGetUniformLocation(GLuint program, const GLchar* name) */
    733         fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
    734         break;
    735     case GLMessage::glGetBooleanv:
    736         fixup_glGetBooleanv(glmsg, pointersToFixup);
    737         break;
    738     case GLMessage::glGetFloatv:
    739         fixup_glGetFloatv(glmsg, pointersToFixup);
    740         break;
    741     case GLMessage::glGetIntegerv:        /* void glGetIntegerv(GLenum pname, GLint *params); */
    742         fixup_GenericIntArray(1, 1, glmsg, pointersToFixup[0]);
    743         break;
    744     case GLMessage::glGetProgramiv:
    745     case GLMessage::glGetRenderbufferParameteriv:
    746     case GLMessage::glGetShaderiv:
    747         /* void glGetProgramiv(GLuint program, GLenum pname, GLint* params) */
    748         /* void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) */
    749         /* void glGetShaderiv(GLuint shader, GLenum pname, GLint* params) */
    750         fixup_GenericIntArray(2, 1, glmsg, pointersToFixup[0]);
    751         break;
    752     case GLMessage::glGetString:
    753         fixup_glGetString(glmsg, pointersToFixup);
    754         break;
    755     case GLMessage::glTexImage2D:
    756         if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
    757             fixup_glTexImage2D(glmsg, pointersToFixup);
    758         }
    759         break;
    760     case GLMessage::glTexSubImage2D:
    761         if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
    762             fixup_glTexSubImage2D(glmsg, pointersToFixup);
    763         }
    764         break;
    765     case GLMessage::glShaderSource:
    766         fixup_glShaderSource(glmsg, pointersToFixup);
    767         break;
    768     case GLMessage::glUniform1iv:
    769         /* void glUniform1iv(GLint location, GLsizei count, const GLint *value); */
    770         fixup_glUniformGenericInteger(2, 1, glmsg, pointersToFixup);
    771         break;
    772     case GLMessage::glUniform2iv:
    773         /* void glUniform2iv(GLint location, GLsizei count, const GLint *value); */
    774         fixup_glUniformGenericInteger(2, 2, glmsg, pointersToFixup);
    775         break;
    776     case GLMessage::glUniform3iv:
    777         /* void glUniform3iv(GLint location, GLsizei count, const GLint *value); */
    778         fixup_glUniformGenericInteger(2, 3, glmsg, pointersToFixup);
    779         break;
    780     case GLMessage::glUniform4iv:
    781         /* void glUniform4iv(GLint location, GLsizei count, const GLint *value); */
    782         fixup_glUniformGenericInteger(2, 4, glmsg, pointersToFixup);
    783         break;
    784     case GLMessage::glUniform1fv:
    785         /* void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); */
    786         fixup_glUniformGeneric(2, 1, glmsg, pointersToFixup[0]);
    787         break;
    788     case GLMessage::glUniform2fv:
    789         /* void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); */
    790         fixup_glUniformGeneric(2, 2, glmsg, pointersToFixup[0]);
    791         break;
    792     case GLMessage::glUniform3fv:
    793         /* void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); */
    794         fixup_glUniformGeneric(2, 3, glmsg, pointersToFixup[0]);
    795         break;
    796     case GLMessage::glUniform4fv:
    797         /* void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); */
    798         fixup_glUniformGeneric(2, 4, glmsg, pointersToFixup[0]);
    799         break;
    800     case GLMessage::glUniformMatrix2fv:
    801         /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
    802                                                                     const GLfloat* value) */
    803         fixup_glUniformMatrixGeneric(2, glmsg, pointersToFixup);
    804         break;
    805     case GLMessage::glUniformMatrix3fv:
    806         /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
    807                                                                     const GLfloat* value) */
    808         fixup_glUniformMatrixGeneric(3, glmsg, pointersToFixup);
    809         break;
    810     case GLMessage::glUniformMatrix4fv:
    811         /* void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
    812                                                                     const GLfloat* value) */
    813         fixup_glUniformMatrixGeneric(4, glmsg, pointersToFixup);
    814         break;
    815     case GLMessage::glBufferData:
    816         /* void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) */
    817         fixup_glBufferData(context, glmsg, pointersToFixup);
    818         break;
    819     case GLMessage::glBufferSubData:
    820         /* void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) */
    821         fixup_glBufferSubData(context, glmsg, pointersToFixup);
    822         break;
    823     case GLMessage::glDrawArrays:
    824         /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
    825         fixup_glDrawArrays(context, glmsg);
    826         break;
    827     case GLMessage::glDrawElements:
    828         /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
    829         fixup_glDrawElements(context, glmsg, pointersToFixup);
    830         break;
    831     case GLMessage::glPushGroupMarkerEXT:
    832         /* void PushGroupMarkerEXT(sizei length, const char *marker); */
    833         fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
    834         break;
    835     case GLMessage::glInsertEventMarkerEXT:
    836         /* void InsertEventMarkerEXT(sizei length, const char *marker); */
    837         fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
    838         break;
    839     default:
    840         break;
    841     }
    842 }
    843 
    844 };
    845 };
    846