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