gltrace_fixup.cpp revision 88e8e5a3f16f0003bd2b43142241b8e1a9a46abe
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
79/** Generic helper function: extract pointer at argIndex and
80    replace it with the C style string at *pointer */
81void fixup_CStringPtr(int argIndex, GLMessage *glmsg) {
82    GLMessage_DataType *arg = glmsg->mutable_args(argIndex);
83    GLchar *ptr = (GLchar *)arg->intvalue(0);
84
85    arg->set_type(GLMessage::DataType::CHAR);
86    arg->set_isarray(true);
87    arg->add_charvalue(ptr);
88}
89
90void fixup_glGetString(GLMessage *glmsg) {
91    /* const GLubyte* GLTrace_glGetString(GLenum name) */
92    GLMessage_DataType *ret = glmsg->mutable_returnvalue();
93    GLchar *ptr = (GLchar *)ret->intvalue(0);
94
95    if (ptr != NULL) {
96        ret->set_type(GLMessage::DataType::CHAR);
97        ret->set_isarray(true);
98        ret->add_charvalue(ptr);
99    }
100}
101
102/* Add the contents of the framebuffer to the protobuf message */
103void fixup_addFBContents(GLTraceContext *context, GLMessage *glmsg, FBBinding fbToRead) {
104    void *fbcontents;
105    unsigned fbsize, fbwidth, fbheight;
106    context->getCompressedFB(&fbcontents, &fbsize, &fbwidth, &fbheight, fbToRead);
107
108    GLMessage_FrameBuffer *fb = glmsg->mutable_fb();
109    fb->set_width(fbwidth);
110    fb->set_height(fbheight);
111    fb->add_contents(fbcontents, fbsize);
112}
113
114/** Common fixup routing for glTexImage2D & glTexSubImage2D. */
115void fixup_glTexImage(int widthIndex, int heightIndex, GLMessage *glmsg) {
116    GLMessage_DataType arg_width  = glmsg->args(widthIndex);
117    GLMessage_DataType arg_height = glmsg->args(heightIndex);
118
119    GLMessage_DataType arg_format = glmsg->args(6);
120    GLMessage_DataType arg_type   = glmsg->args(7);
121    GLMessage_DataType *arg_data  = glmsg->mutable_args(8);
122
123    GLsizei width  = arg_width.intvalue(0);
124    GLsizei height = arg_height.intvalue(0);
125    GLenum format  = arg_format.intvalue(0);
126    GLenum type    = arg_type.intvalue(0);
127    void *data     = (void *)arg_data->intvalue(0);
128
129    int bytesPerTexel = getBytesPerTexel(format, type);
130
131    arg_data->set_type(GLMessage::DataType::BYTE);
132    arg_data->clear_rawbytes();
133
134    if (data != NULL) {
135        arg_data->set_isarray(true);
136        arg_data->add_rawbytes(data, bytesPerTexel * width * height);
137    } else {
138        arg_data->set_isarray(false);
139        arg_data->set_type(GLMessage::DataType::VOID);
140    }
141}
142
143
144void fixup_glTexImage2D(GLMessage *glmsg) {
145    /* void glTexImage2D(GLenum target,
146                        GLint level,
147                        GLint internalformat,
148                        GLsizei width,
149                        GLsizei height,
150                        GLint border,
151                        GLenum format,
152                        GLenum type,
153                        const GLvoid *data);
154    */
155    int widthIndex = 3;
156    int heightIndex = 4;
157    fixup_glTexImage(widthIndex, heightIndex, glmsg);
158}
159
160void fixup_glTexSubImage2D(GLMessage *glmsg) {
161    /*
162    void glTexSubImage2D(GLenum target,
163                        GLint level,
164                        GLint xoffset,
165                        GLint yoffset,
166                        GLsizei width,
167                        GLsizei height,
168                        GLenum format,
169                        GLenum type,
170                        const GLvoid * data);
171    */
172    int widthIndex = 4;
173    int heightIndex = 5;
174    fixup_glTexImage(widthIndex, heightIndex, glmsg);
175}
176
177void fixup_glShaderSource(GLMessage *glmsg) {
178    /* void glShaderSource(GLuint shader, GLsizei count, const GLchar** string,
179                                    const GLint* length) */
180    GLMessage_DataType arg_count  = glmsg->args(1);
181    GLMessage_DataType arg_lenp   = glmsg->args(3);
182    GLMessage_DataType *arg_strpp = glmsg->mutable_args(2);
183
184    GLsizei count = arg_count.intvalue(0);
185    GLchar **stringpp = (GLchar **)arg_strpp->intvalue(0);
186    GLint *lengthp = (GLint *)arg_lenp.intvalue(0);
187
188    arg_strpp->set_type(GLMessage::DataType::CHAR);
189    arg_strpp->set_isarray(true);
190    arg_strpp->clear_charvalue();
191
192    ::std::string src = "";
193    for (int i = 0; i < count; i++) {
194        if (lengthp != NULL)
195            src.append(*stringpp, *lengthp);
196        else
197            src.append(*stringpp);  // assume null terminated
198        stringpp++;
199        lengthp++;
200    }
201
202    arg_strpp->add_charvalue(src);
203}
204
205void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg) {
206    /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */
207    GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex);
208    GLint *src = (GLint*)arg_values->intvalue(0);
209
210    arg_values->set_type(GLMessage::DataType::INT);
211    arg_values->set_isarray(true);
212    arg_values->clear_intvalue();
213
214    for (int i = 0; i < nIntegers; i++) {
215        arg_values->add_intvalue(*src++);
216    }
217}
218
219void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg) {
220    GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex);
221    GLfloat *src = (GLfloat*)arg_values->intvalue(0);
222
223    arg_values->set_type(GLMessage::DataType::FLOAT);
224    arg_values->set_isarray(true);
225    arg_values->clear_floatvalue();
226
227    for (int i = 0; i < nFloats; i++) {
228        arg_values->add_floatvalue(*src++);
229    }
230}
231
232void fixup_glUniformMatrixGeneric(int matrixSize, GLMessage *glmsg) {
233    /* void glUniformMatrix?fv(GLint location, GLsizei count, GLboolean transpose,
234                                                                const GLfloat* value) */
235    GLMessage_DataType arg_count  = glmsg->args(1);
236    int n_matrices = arg_count.intvalue(0);
237    fixup_glUniformGeneric(3, matrixSize * matrixSize * n_matrices, glmsg);
238}
239
240void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg) {
241    GLMessage_DataType *arg_intarray = glmsg->mutable_args(argIndex);
242    GLint *intp = (GLint *)arg_intarray->intvalue(0);
243
244    if (intp == NULL) {
245        return;
246    }
247
248    arg_intarray->set_type(GLMessage::DataType::INT);
249    arg_intarray->set_isarray(true);
250    arg_intarray->clear_intvalue();
251
252    for (int i = 0; i < nInts; i++, intp++) {
253        arg_intarray->add_intvalue(*intp);
254    }
255}
256
257void fixup_GenericEnumArray(int argIndex, int nEnums, GLMessage *glmsg) {
258    // fixup as if they were ints
259    fixup_GenericIntArray(argIndex, nEnums, glmsg);
260
261    // and then set the data type to be enum
262    GLMessage_DataType *arg_enumarray = glmsg->mutable_args(argIndex);
263    arg_enumarray->set_type(GLMessage::DataType::ENUM);
264}
265
266void fixup_glGenGeneric(GLMessage *glmsg) {
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);
272}
273
274void fixup_glDeleteGeneric(GLMessage *glmsg) {
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);
280}
281
282void fixup_glGetBooleanv(GLMessage *glmsg) {
283    /* void glGetBooleanv(GLenum pname, GLboolean *params); */
284    GLMessage_DataType *arg_params = glmsg->mutable_args(1);
285    GLboolean *src = (GLboolean*)arg_params->intvalue(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) {
294    /* void glGetFloatv(GLenum pname, GLfloat *params); */
295    GLMessage_DataType *arg_params = glmsg->mutable_args(1);
296    GLfloat *src = (GLfloat*)arg_params->intvalue(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 in the call.
342 */
343int getShaderVariableLocation(GLTraceContext *context, GLMessage *glmsg) {
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    GLchar *name = (GLchar*) glmsg->args(6).intvalue(0);
351
352    if (func == GLMessage::glGetActiveAttrib) {
353        return context->hooks->gl.glGetAttribLocation(program, name);
354    } else {
355        return context->hooks->gl.glGetUniformLocation(program, name);
356    }
357}
358
359void fixup_glGetActiveAttribOrUniform(GLMessage *glmsg, int location) {
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);     // length
366    fixup_GenericIntArray(4, 1, glmsg);     // size
367    fixup_GenericEnumArray(5, 1, glmsg);    // type
368    fixup_CStringPtr(6, glmsg);             // 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    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
382void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessage *glmsg) {
383    // for all messages, set the current context id
384    glmsg->set_context_id(context->getId());
385
386    // set start time and duration
387    glmsg->set_start_time(start);
388    glmsg->set_duration((unsigned)(end - start));
389
390    // do any custom message dependent processing
391    switch (glmsg->function()) {
392    case GLMessage::glDeleteBuffers:      /* glDeleteBuffers(GLsizei n, GLuint *buffers); */
393    case GLMessage::glDeleteFramebuffers: /* glDeleteFramebuffers(GLsizei n, GLuint *buffers); */
394    case GLMessage::glDeleteRenderbuffers:/* glDeleteRenderbuffers(GLsizei n, GLuint *buffers); */
395    case GLMessage::glDeleteTextures:     /* glDeleteTextures(GLsizei n, GLuint *textures); */
396        fixup_glDeleteGeneric(glmsg);
397        break;
398    case GLMessage::glGenBuffers:        /* void glGenBuffers(GLsizei n, GLuint *buffers); */
399    case GLMessage::glGenFramebuffers:   /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
400    case GLMessage::glGenRenderbuffers:  /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
401    case GLMessage::glGenTextures:       /* void glGenTextures(GLsizei n, GLuint *textures); */
402        fixup_glGenGeneric(glmsg);
403        break;
404    case GLMessage::glLinkProgram:       /* void glLinkProgram(GLuint program); */
405        fixup_glLinkProgram(glmsg);
406        break;
407    case GLMessage::glGetActiveAttrib:
408        fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg));
409        break;
410    case GLMessage::glGetActiveUniform:
411        fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg));
412        break;
413    case GLMessage::glBindAttribLocation:
414        /* void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); */
415        fixup_CStringPtr(2, glmsg);
416        break;
417    case GLMessage::glGetAttribLocation:
418    case GLMessage::glGetUniformLocation:
419        /* int glGetAttribLocation(GLuint program, const GLchar* name) */
420        /* int glGetUniformLocation(GLuint program, const GLchar* name) */
421        fixup_CStringPtr(1, glmsg);
422        break;
423    case GLMessage::glGetBooleanv:
424        fixup_glGetBooleanv(glmsg);
425        break;
426    case GLMessage::glGetFloatv:
427        fixup_glGetFloatv(glmsg);
428        break;
429    case GLMessage::glGetIntegerv:        /* void glGetIntegerv(GLenum pname, GLint *params); */
430        fixup_GenericIntArray(1, 1, glmsg);
431        break;
432    case GLMessage::glGetProgramiv:
433    case GLMessage::glGetRenderbufferParameteriv:
434    case GLMessage::glGetShaderiv:
435        /* void glGetProgramiv(GLuint program, GLenum pname, GLint* params) */
436        /* void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) */
437        /* void glGetShaderiv(GLuint shader, GLenum pname, GLint* params) */
438        fixup_GenericIntArray(2, 1, glmsg);
439        break;
440    case GLMessage::glGetString:
441        fixup_glGetString(glmsg);
442        break;
443    case GLMessage::glTexImage2D:
444        if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
445            fixup_glTexImage2D(glmsg);
446        }
447        break;
448    case GLMessage::glTexSubImage2D:
449        if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
450            fixup_glTexSubImage2D(glmsg);
451        }
452        break;
453    case GLMessage::glShaderSource:
454        fixup_glShaderSource(glmsg);
455        break;
456    case GLMessage::glUniform1iv:
457        /* void glUniform1iv(GLint location, GLsizei count, const GLint *value); */
458        fixup_glUniformGenericInteger(2, 1, glmsg);
459        break;
460    case GLMessage::glUniform2iv:
461        /* void glUniform2iv(GLint location, GLsizei count, const GLint *value); */
462        fixup_glUniformGenericInteger(2, 2, glmsg);
463        break;
464    case GLMessage::glUniform3iv:
465        /* void glUniform3iv(GLint location, GLsizei count, const GLint *value); */
466        fixup_glUniformGenericInteger(2, 3, glmsg);
467        break;
468    case GLMessage::glUniform4iv:
469        /* void glUniform4iv(GLint location, GLsizei count, const GLint *value); */
470        fixup_glUniformGenericInteger(2, 4, glmsg);
471        break;
472    case GLMessage::glUniform1fv:
473        /* void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); */
474        fixup_glUniformGeneric(2, 1, glmsg);
475        break;
476    case GLMessage::glUniform2fv:
477        /* void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); */
478        fixup_glUniformGeneric(2, 2, glmsg);
479        break;
480    case GLMessage::glUniform3fv:
481        /* void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); */
482        fixup_glUniformGeneric(2, 3, glmsg);
483        break;
484    case GLMessage::glUniform4fv:
485        /* void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); */
486        fixup_glUniformGeneric(2, 4, glmsg);
487        break;
488    case GLMessage::glUniformMatrix2fv:
489        /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
490                                                                    const GLfloat* value) */
491        fixup_glUniformMatrixGeneric(2, glmsg);
492        break;
493    case GLMessage::glUniformMatrix3fv:
494        /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
495                                                                    const GLfloat* value) */
496        fixup_glUniformMatrixGeneric(3, glmsg);
497        break;
498    case GLMessage::glUniformMatrix4fv:
499        /* void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
500                                                                    const GLfloat* value) */
501        fixup_glUniformMatrixGeneric(4, glmsg);
502        break;
503    case GLMessage::glDrawArrays:
504        /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
505        if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
506            fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
507        }
508        break;
509    case GLMessage::glDrawElements:
510        /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
511        if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
512            fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
513        }
514        break;
515    case GLMessage::glPushGroupMarkerEXT:
516        /* void PushGroupMarkerEXT(sizei length, const char *marker); */
517        fixup_CStringPtr(1, glmsg);
518        break;
519    case GLMessage::glInsertEventMarkerEXT:
520        /* void InsertEventMarkerEXT(sizei length, const char *marker); */
521        fixup_CStringPtr(1, glmsg);
522        break;
523    default:
524        break;
525    }
526}
527
528};
529};
530