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 <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 
     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 
     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 
     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 
    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 */
    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 
    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 */
    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. */
    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 
    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 
    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 
    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 
    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 
    254 void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg, void *src) {
    255     fixup_GenericFloatArray(argIndex, nFloats, glmsg, src);
    256 }
    257 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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 
    383 GLint glGetInteger(GLTraceContext *context, GLenum param) {
    384     GLint x;
    385     context->hooks->gl.glGetIntegerv(param, &x);
    386     return x;
    387 }
    388 
    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 
    395 bool isUsingArrayBuffers(GLTraceContext *context) {
    396     return glGetInteger(context, GL_ARRAY_BUFFER_BINDING) != 0;
    397 }
    398 
    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. */
    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 
    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 
    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. */
    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. */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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