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