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