gltrace_fixup.cpp revision e6f43ddce78d6846af12550ff9193c5c6fe5844b
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 <GLES2/gl2.h>
19
20#include "gltrace.pb.h"
21#include "gltrace_context.h"
22#include "gltrace_fixup.h"
23
24namespace android {
25namespace gltrace {
26
27unsigned getBytesPerTexel(const GLenum format, const GLenum type) {
28    /*
29    Description from glTexImage2D spec:
30
31    Data is read from data as a sequence of unsigned bytes or shorts, depending on type.
32    When type is GL_UNSIGNED_BYTE, each of the bytes is interpreted as one color component.
33    When type is one of GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, or
34    GL_UNSIGNED_SHORT_5_5_5_1, each unsigned short value is interpreted as containing all
35    the components for a single texel, with the color components arranged according to
36    format. Color components are treated as groups of one, two, three, or four values,
37    again based on format. Groups of components are referred to as texels.
38
39    width × height texels are read from memory, starting at location data. By default,
40    these texels are taken from adjacent memory locations, except that after all width
41    texels are read, the read pointer is advanced to the next four-byte boundary.
42    The four-byte row alignment is specified by glPixelStorei with argument
43    GL_UNPACK_ALIGNMENT, and it can be set to one, two, four, or eight bytes.
44    */
45
46    switch (type) {
47    case GL_UNSIGNED_SHORT_5_6_5:
48    case GL_UNSIGNED_SHORT_4_4_4_4:
49    case GL_UNSIGNED_SHORT_5_5_5_1:
50        return 2;
51    case GL_UNSIGNED_BYTE:
52        break;
53    default:
54        ALOGE("GetBytesPerPixel: unknown type %x", type);
55    }
56
57    switch (format) {
58    case GL_ALPHA:
59    case GL_LUMINANCE:
60        return 1;
61    case GL_LUMINANCE_ALPHA:
62        return 2;
63    case GL_RGB:
64        return 3;
65    case GL_RGBA:
66    case 0x80E1: // GL_BGRA_EXT
67        return 4;
68    default:
69        ALOGE("GetBytesPerPixel: unknown format %x", format);
70    }
71
72    return 1;   // in doubt...
73}
74
75/** Generic helper function: extract pointer at argIndex and
76    replace it with the C style string at *pointer */
77void fixup_CStringPtr(int argIndex, GLMessage *glmsg) {
78    GLMessage_DataType *arg = glmsg->mutable_args(argIndex);
79    GLchar *ptr = (GLchar *)arg->intvalue(0);
80
81    arg->set_type(GLMessage::DataType::CHAR);
82    arg->set_isarray(true);
83    arg->add_charvalue(ptr);
84}
85
86void fixup_glGetString(GLMessage *glmsg) {
87    /* const GLubyte* GLTrace_glGetString(GLenum name) */
88    GLMessage_DataType *ret = glmsg->mutable_returnvalue();
89    GLchar *ptr = (GLchar *)ret->intvalue(0);
90
91    if (ptr != NULL) {
92        ret->set_type(GLMessage::DataType::CHAR);
93        ret->set_isarray(true);
94        ret->add_charvalue(ptr);
95    }
96}
97
98/* Add the contents of the framebuffer to the protobuf message */
99void fixup_addFBContents(GLTraceContext *context, GLMessage *glmsg, FBBinding fbToRead) {
100    void *fbcontents;
101    unsigned fbsize, fbwidth, fbheight;
102    context->getCompressedFB(&fbcontents, &fbsize, &fbwidth, &fbheight, fbToRead);
103
104    GLMessage_FrameBuffer *fb = glmsg->mutable_fb();
105    fb->set_width(fbwidth);
106    fb->set_height(fbheight);
107    fb->add_contents(fbcontents, fbsize);
108}
109
110void fixup_glTexImage2D(GLMessage *glmsg) {
111    /* void glTexImage2D(GLenum target,
112                        GLint level,
113                        GLint internalformat,
114                        GLsizei width,
115                        GLsizei height,
116                        GLint border,
117                        GLenum format,
118                        GLenum type,
119                        const GLvoid *data);
120     */
121    GLMessage_DataType arg_width  = glmsg->args(3);
122    GLMessage_DataType arg_height = glmsg->args(4);
123    GLMessage_DataType arg_format = glmsg->args(6);
124    GLMessage_DataType arg_type   = glmsg->args(7);
125    GLMessage_DataType *arg_data  = glmsg->mutable_args(8);
126
127    GLsizei width  = arg_width.intvalue(0);
128    GLsizei height = arg_height.intvalue(0);
129    GLenum format  = arg_format.intvalue(0);
130    GLenum type    = arg_type.intvalue(0);
131    void *data     = (void *)arg_data->intvalue(0);
132
133    int bytesPerTexel = getBytesPerTexel(format, type);
134
135    arg_data->set_type(GLMessage::DataType::BYTE);
136    arg_data->set_isarray(true);
137    arg_data->clear_rawbytes();
138
139    if (data != NULL) {
140        arg_data->add_rawbytes(data, bytesPerTexel * width * height);
141    } else {
142        ALOGE("fixup_glTexImage2D: image data is NULL.\n");
143        arg_data->set_type(GLMessage::DataType::VOID);
144        // FIXME:
145        // This will create the texture, but it will be uninitialized.
146        // It can later be initialized with glTexSubImage2D or by
147        // attaching an FBO to it and rendering into the FBO.
148    }
149}
150
151void fixup_glShaderSource(GLMessage *glmsg) {
152    /* void glShaderSource(GLuint shader, GLsizei count, const GLchar** string,
153                                    const GLint* length) */
154    GLMessage_DataType arg_count  = glmsg->args(1);
155    GLMessage_DataType arg_lenp   = glmsg->args(3);
156    GLMessage_DataType *arg_strpp = glmsg->mutable_args(2);
157
158    GLsizei count = arg_count.intvalue(0);
159    GLchar **stringpp = (GLchar **)arg_strpp->intvalue(0);
160    GLint *lengthp = (GLint *)arg_lenp.intvalue(0);
161
162    arg_strpp->set_type(GLMessage::DataType::CHAR);
163    arg_strpp->set_isarray(true);
164    arg_strpp->clear_charvalue();
165
166    ::std::string src = "";
167    for (int i = 0; i < count; i++) {
168        if (lengthp != NULL)
169            src.append(*stringpp, *lengthp);
170        else
171            src.append(*stringpp);  // assume null terminated
172        stringpp++;
173        lengthp++;
174    }
175
176    arg_strpp->add_charvalue(src);
177}
178
179void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg) {
180    GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex);
181    GLfloat *src = (GLfloat*)arg_values->intvalue(0);
182
183    arg_values->set_type(GLMessage::DataType::FLOAT);
184    arg_values->set_isarray(true);
185    arg_values->clear_floatvalue();
186
187    for (int i = 0; i < nFloats; i++) {
188        arg_values->add_floatvalue(*src++);
189    }
190}
191
192void fixup_glUniformMatrixGeneric(int matrixSize, GLMessage *glmsg) {
193    /* void glUniformMatrix?fv(GLint location, GLsizei count, GLboolean transpose,
194                                                                const GLfloat* value) */
195    GLMessage_DataType arg_count  = glmsg->args(1);
196    int n_matrices = arg_count.intvalue(0);
197    fixup_glUniformGeneric(3, matrixSize * matrixSize * n_matrices, glmsg);
198}
199
200void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg) {
201    GLMessage_DataType *arg_intarray = glmsg->mutable_args(argIndex);
202    GLint *intp = (GLint *)arg_intarray->intvalue(0);
203
204    arg_intarray->set_type(GLMessage::DataType::INT);
205    arg_intarray->set_isarray(true);
206    arg_intarray->clear_intvalue();
207
208    for (int i = 0; i < nInts; i++, intp++) {
209        arg_intarray->add_intvalue(*intp);
210    }
211}
212
213void fixup_glGenGeneric(GLMessage *glmsg) {
214    /* void glGen*(GLsizei n, GLuint * buffers); */
215    GLMessage_DataType arg_n  = glmsg->args(0);
216    GLsizei n = arg_n.intvalue(0);
217
218    fixup_GenericIntArray(1, n, glmsg);
219}
220
221void fixup_glGetBooleanv(GLMessage *glmsg) {
222    /* void glGetBooleanv(GLenum pname, GLboolean *params); */
223    GLMessage_DataType *arg_params = glmsg->mutable_args(1);
224    GLboolean *src = (GLboolean*)arg_params->intvalue(0);
225
226    arg_params->set_type(GLMessage::DataType::BOOL);
227    arg_params->set_isarray(true);
228    arg_params->clear_boolvalue();
229    arg_params->add_boolvalue(*src);
230}
231
232void fixup_glGetFloatv(GLMessage *glmsg) {
233    /* void glGetFloatv(GLenum pname, GLfloat *params); */
234    GLMessage_DataType *arg_params = glmsg->mutable_args(1);
235    GLfloat *src = (GLfloat*)arg_params->intvalue(0);
236
237    arg_params->set_type(GLMessage::DataType::FLOAT);
238    arg_params->set_isarray(true);
239    arg_params->clear_floatvalue();
240    arg_params->add_floatvalue(*src);
241}
242
243void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessage *glmsg) {
244    // for all messages, set the current context id
245    glmsg->set_context_id(context->getId());
246
247    // set start time and duration
248    glmsg->set_start_time(start);
249    glmsg->set_duration((unsigned)(end - start));
250
251    // do any custom message dependent processing
252    switch (glmsg->function()) {
253    case GLMessage::glGenBuffers:        /* void glGenBuffers(GLsizei n, GLuint * buffers); */
254    case GLMessage::glGenFramebuffers:   /* void glGenFramebuffers(GLsizei n, GLuint * buffers); */
255    case GLMessage::glGenRenderbuffers:  /* void glGenFramebuffers(GLsizei n, GLuint * buffers); */
256    case GLMessage::glGenTextures:       /* void glGenTextures(GLsizei n, GLuint * buffers); */
257        fixup_glGenGeneric(glmsg);
258        break;
259    case GLMessage::glGetAttribLocation:
260    case GLMessage::glGetUniformLocation:
261        /* int glGetAttribLocation(GLuint program, const GLchar* name) */
262        /* int glGetUniformLocation(GLuint program, const GLchar* name) */
263        fixup_CStringPtr(1, glmsg);
264        break;
265    case GLMessage::glGetBooleanv:
266        fixup_glGetBooleanv(glmsg);
267        break;
268    case GLMessage::glGetFloatv:
269        fixup_glGetFloatv(glmsg);
270        break;
271    case GLMessage::glGetIntegerv:        /* void glGetIntegerv(GLenum pname, GLint *params); */
272        fixup_GenericIntArray(1, 1, glmsg);
273        break;
274    case GLMessage::glGetProgramiv:
275    case GLMessage::glGetRenderbufferParameteriv:
276    case GLMessage::glGetShaderiv:
277        /* void glGetProgramiv(GLuint program, GLenum pname, GLint* params) */
278        /* void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) */
279        /* void glGetShaderiv(GLuint shader, GLenum pname, GLint* params) */
280        fixup_GenericIntArray(2, 1, glmsg);
281        break;
282    case GLMessage::glGetString:
283        fixup_glGetString(glmsg);
284        break;
285    case GLMessage::glTexImage2D:
286        if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
287            fixup_glTexImage2D(glmsg);
288        }
289        break;
290    case GLMessage::glShaderSource:
291        fixup_glShaderSource(glmsg);
292        break;
293    case GLMessage::glUniformMatrix2fv:
294        /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
295                                                                    const GLfloat* value) */
296        fixup_glUniformMatrixGeneric(2, glmsg);
297        break;
298    case GLMessage::glUniformMatrix3fv:
299        /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
300                                                                    const GLfloat* value) */
301        fixup_glUniformMatrixGeneric(3, glmsg);
302        break;
303    case GLMessage::glUniformMatrix4fv:
304        /* void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
305                                                                    const GLfloat* value) */
306        fixup_glUniformMatrixGeneric(4, glmsg);
307        break;
308    case GLMessage::glDrawArrays:
309        /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
310        if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
311            fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
312        }
313        break;
314    case GLMessage::glDrawElements:
315        /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
316        if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
317            fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
318        }
319        break;
320    default:
321        break;
322    }
323}
324
325};
326};
327