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 "frameworks/native/opengl/libs/GLES_trace/proto/gltrace.pb.h"
25#include "gltrace_api.h"
26#include "gltrace_context.h"
27#include "gltrace_fixup.h"
28
29namespace android {
30namespace gltrace {
31
32GLint glGetInteger(GLTraceContext *context, GLenum param) {
33    GLint x;
34    context->hooks->gl.glGetIntegerv(param, &x);
35    return x;
36}
37
38GLint glGetVertexAttrib(GLTraceContext *context, GLuint index, GLenum pname) {
39    GLint x;
40    context->hooks->gl.glGetVertexAttribiv(index, pname, &x);
41    return x;
42}
43
44bool 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
51bool isUsingArrayBuffers(GLTraceContext *context) {
52    return glGetInteger(context, GL_ARRAY_BUFFER_BINDING) != 0;
53}
54
55bool isUsingElementArrayBuffers(GLTraceContext *context) {
56    return glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING) != 0;
57}
58
59unsigned 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
107void 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
124void 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
141void 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 */
152void 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
161void 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 */
174void 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. */
186void 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
216void 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
232void 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
249void 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
276void 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
304void 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
330void 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
338void 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
344void 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
352void 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
360void 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
368void 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
379void 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
390void 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 */
429GLint 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
444void 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. */
470void 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
478void 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
497void 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. */
513int 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. */
536void 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
611void 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
633void 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
660void 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
676void 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
714void 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
724void 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
756void 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