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