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