trace.cpp revision 6132b3703da76389e81d26b0023846a78b008603
1/*
2 ** Copyright 2010, 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#if EGL_TRACE
18
19#include <stdarg.h>
20#include <stdlib.h>
21
22#include <EGL/egl.h>
23#include <EGL/eglext.h>
24#include <GLES/gl.h>
25#include <GLES/glext.h>
26
27#include <cutils/log.h>
28
29#include "hooks.h"
30
31// ----------------------------------------------------------------------------
32namespace android {
33// ----------------------------------------------------------------------------
34
35struct GLenumString {
36    GLenum e;
37    const char* s;
38};
39
40#undef GL_ENUM
41#define GL_ENUM(VAL,NAME) {VAL, #NAME},
42
43static GLenumString g_enumnames[] = {
44#include "enums.in"
45};
46#undef GL_ENUM
47
48static int compareGLEnum(const void* a, const void* b) {
49    return ((const GLenumString*) a)->e - ((const GLenumString*) b)->e;
50}
51
52static const char* GLEnumToString(GLenum e) {
53    GLenumString key = {e, ""};
54    const GLenumString* result = (const GLenumString*) bsearch(
55        &key, g_enumnames,
56        sizeof(g_enumnames) / sizeof(g_enumnames[0]),
57        sizeof(g_enumnames[0]), compareGLEnum);
58    if (result) {
59        return result->s;
60    }
61    return NULL;
62}
63
64static const char* GLbooleanToString(GLboolean arg) {
65    return arg ? "GL_TRUE" : "GL_FALSE";
66}
67
68static GLenumString g_bitfieldNames[] = {
69    {0x00004000, "GL_COLOR_BUFFER_BIT"},
70    {0x00000400, "GL_STENCIL_BUFFER_BIT"},
71    {0x00000100, "GL_DEPTH_BUFFER_BIT"}
72};
73
74class StringBuilder {
75    static const int lineSize = 500;
76    char line[lineSize];
77    int line_index;
78public:
79    StringBuilder() {
80        line_index = 0;
81        line[0] = '\0';
82    }
83    void append(const char* fmt, ...) {
84        va_list argp;
85        va_start(argp, fmt);
86        line_index += vsnprintf(line + line_index, lineSize-line_index, fmt, argp);
87        va_end(argp);
88    }
89    const char* getString() {
90        line_index = 0;
91        line[lineSize-1] = '\0';
92        return line;
93    }
94};
95
96
97static void TraceGLShaderSource(GLuint shader, GLsizei count,
98    const GLchar** string, const GLint* length) {
99    LOGD("const char* shaderSrc[] = {");
100    for (GLsizei i = 0; i < count; i++) {
101        const char* comma = i < count-1 ? "," : "";
102        const GLchar* s = string[i];
103        if (length) {
104            GLint len = length[i];
105            LOGD("    \"%*s\"%s", len, s, comma);
106        } else {
107            LOGD("    \"%s\"%s", s, comma);
108        }
109    }
110    LOGD("};");
111    if (length) {
112        LOGD("const GLint* shaderLength[] = {");
113        for (GLsizei i = 0; i < count; i++) {
114            const char* comma = i < count-1 ? "," : "";
115            GLint len = length[i];
116            LOGD("    \"%d\"%s", len, comma);
117        }
118        LOGD("};");
119        LOGD("glShaderSource(%u, %u, shaderSrc, shaderLength);",
120            shader, count);
121    } else {
122        LOGD("glShaderSource(%u, %u, shaderSrc, (const GLint*) 0);",
123            shader, count);
124    }
125}
126
127static void TraceValue(int elementCount, char type,
128        GLsizei chunkCount, GLsizei chunkSize, const void* value) {
129    StringBuilder stringBuilder;
130    GLsizei count = chunkCount * chunkSize;
131    bool isFloat = type == 'f';
132    const char* typeString = isFloat ? "GLfloat" : "GLint";
133    LOGD("const %s value[] = {", typeString);
134    for (GLsizei i = 0; i < count; i++) {
135        StringBuilder builder;
136        builder.append("    ");
137        for (int e = 0; e < elementCount; e++) {
138            const char* comma = ", ";
139            if (e == elementCount-1) {
140                if (i == count - 1) {
141                    comma = "";
142                } else {
143                    comma = ",";
144                }
145            }
146            if (isFloat) {
147                builder.append("%g%s", * (GLfloat*) value, comma);
148                value = (void*) (((GLfloat*) value) + 1);
149            } else {
150                builder.append("%d%s", * (GLint*) value, comma);
151                value = (void*) (((GLint*) value) + 1);
152            }
153        }
154        LOGD("%s", builder.getString());
155        if (chunkSize > 1 && i < count-1
156                && (i % chunkSize) == (chunkSize-1)) {
157            LOGD("%s", ""); // Print a blank line.
158        }
159    }
160    LOGD("};");
161}
162
163static void TraceUniformv(int elementCount, char type,
164        GLuint location, GLsizei count, const void* value) {
165    TraceValue(elementCount, type, count, 1, value);
166    LOGD("glUniform%d%c(%u, %u, value);", elementCount, type, location, count);
167}
168
169static void TraceUniformMatrix(int matrixSideLength,
170        GLuint location, GLsizei count, GLboolean transpose, const void* value) {
171    TraceValue(matrixSideLength, 'f', count, matrixSideLength, value);
172    LOGD("glUniformMatrix%dfv(%u, %u, %s, value);", matrixSideLength, location, count,
173            GLbooleanToString(transpose));
174}
175
176static void TraceGL(const char* name, int numArgs, ...) {
177    va_list argp;
178    va_start(argp, numArgs);
179    int nameLen = strlen(name);
180
181    // glShaderSource
182    if (nameLen == 14 && strcmp(name, "glShaderSource") == 0) {
183        va_arg(argp, const char*);
184        GLuint shader = va_arg(argp, GLuint);
185        va_arg(argp, const char*);
186        GLsizei count = va_arg(argp, GLsizei);
187        va_arg(argp, const char*);
188        const GLchar** string = (const GLchar**) va_arg(argp, void*);
189        va_arg(argp, const char*);
190        const GLint* length = (const GLint*) va_arg(argp, void*);
191        va_end(argp);
192        TraceGLShaderSource(shader, count, string, length);
193        return;
194    }
195
196    // glUniformXXv
197
198    if (nameLen == 12 && strncmp(name, "glUniform", 9) == 0 && name[11] == 'v') {
199        int elementCount = name[9] - '0'; // 1..4
200        char type = name[10]; // 'f' or 'i'
201        va_arg(argp, const char*);
202        GLuint location = va_arg(argp, GLuint);
203        va_arg(argp, const char*);
204        GLsizei count = va_arg(argp, GLsizei);
205        va_arg(argp, const char*);
206        const void* value = (const void*) va_arg(argp, void*);
207        va_end(argp);
208        TraceUniformv(elementCount, type, location, count, value);
209        return;
210    }
211
212    // glUniformMatrixXfv
213
214    if (nameLen == 18 && strncmp(name, "glUniformMatrix", 15) == 0
215            && name[16] == 'f' && name[17] == 'v') {
216        int matrixSideLength = name[15] - '0'; // 2..4
217        va_arg(argp, const char*);
218        GLuint location = va_arg(argp, GLuint);
219        va_arg(argp, const char*);
220        GLsizei count = va_arg(argp, GLsizei);
221        va_arg(argp, const char*);
222        GLboolean transpose = (GLboolean) va_arg(argp, int);
223        va_arg(argp, const char*);
224        const void* value = (const void*) va_arg(argp, void*);
225        va_end(argp);
226        TraceUniformMatrix(matrixSideLength, location, count, transpose, value);
227        return;
228    }
229
230    StringBuilder builder;
231    builder.append("%s(", name);
232    for (int i = 0; i < numArgs; i++) {
233        if (i > 0) {
234            builder.append(", ");
235        }
236        const char* type = va_arg(argp, const char*);
237        bool isPtr = type[strlen(type)-1] == '*'
238            || strcmp(type, "GLeglImageOES") == 0;
239        if (isPtr) {
240            const void* arg = va_arg(argp, const void*);
241            builder.append("(%s) 0x%08x", type, (size_t) arg);
242        } else if (strcmp(type, "GLbitfield") == 0) {
243            size_t arg = va_arg(argp, size_t);
244            bool first = true;
245            for (size_t i = 0; i < sizeof(g_bitfieldNames) / sizeof(g_bitfieldNames[0]); i++) {
246                const GLenumString* b = &g_bitfieldNames[i];
247                if (b->e & arg) {
248                    if (first) {
249                        first = false;
250                    } else {
251                        builder.append(" | ");
252                    }
253                    builder.append("%s", b->s);
254                    arg &= ~b->e;
255                }
256            }
257            if (first || arg != 0) {
258                if (!first) {
259                    builder.append(" | ");
260                }
261                builder.append("0x%08x", arg);
262            }
263        } else if (strcmp(type, "GLboolean") == 0) {
264            GLboolean arg = va_arg(argp, int);
265            builder.append("%s", GLbooleanToString(arg));
266        } else if (strcmp(type, "GLclampf") == 0) {
267            double arg = va_arg(argp, double);
268            builder.append("%g", arg);
269        } else if (strcmp(type, "GLenum") == 0) {
270            GLenum arg = va_arg(argp, int);
271            const char* s = GLEnumToString(arg);
272            if (s) {
273                builder.append("%s", s);
274            } else {
275                builder.append("0x%x", arg);
276            }
277        } else if (strcmp(type, "GLfixed") == 0) {
278            int arg = va_arg(argp, int);
279            builder.append("0x%08x", arg);
280        } else if (strcmp(type, "GLfloat") == 0) {
281            double arg = va_arg(argp, double);
282            builder.append("%g", arg);
283        } else if (strcmp(type, "GLint") == 0) {
284            int arg = va_arg(argp, int);
285            const char* s = NULL;
286            if (strcmp(name, "glTexParameteri") == 0) {
287                s = GLEnumToString(arg);
288            }
289            if (s) {
290                builder.append("%s", s);
291            } else {
292                builder.append("%d", arg);
293            }
294        } else if (strcmp(type, "GLintptr") == 0) {
295            int arg = va_arg(argp, unsigned int);
296            builder.append("%u", arg);
297        } else if (strcmp(type, "GLsizei") == 0) {
298            int arg = va_arg(argp, size_t);
299            builder.append("%u", arg);
300        } else if (strcmp(type, "GLsizeiptr") == 0) {
301            int arg = va_arg(argp, size_t);
302            builder.append("%u", arg);
303        } else if (strcmp(type, "GLuint") == 0) {
304            int arg = va_arg(argp, unsigned int);
305            builder.append("%u", arg);
306        } else {
307            builder.append("/* ??? %s */", type);
308            break;
309        }
310    }
311    builder.append(");");
312    LOGD("%s", builder.getString());
313    va_end(argp);
314}
315
316#undef TRACE_GL_VOID
317#undef TRACE_GL
318
319#define TRACE_GL_VOID(_api, _args, _argList, ...)                         \
320static void Tracing_ ## _api _args {                                      \
321    TraceGL(#_api, __VA_ARGS__);                                          \
322    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
323    _c->_api _argList;                                                    \
324}
325
326#define TRACE_GL(_type, _api, _args, _argList, ...)                       \
327static _type Tracing_ ## _api _args {                                     \
328    TraceGL(#_api, __VA_ARGS__);                                          \
329    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
330    return _c->_api _argList;                                             \
331}
332
333extern "C" {
334#include "../trace.in"
335}
336#undef TRACE_GL_VOID
337#undef TRACE_GL
338
339#define GL_ENTRY(_r, _api, ...) Tracing_ ## _api,
340
341EGLAPI gl_hooks_t gHooksTrace = {
342    {
343        #include "entries.in"
344    },
345    {
346        {0}
347    }
348};
349#undef GL_ENTRY
350
351// ----------------------------------------------------------------------------
352}; // namespace android
353// ----------------------------------------------------------------------------
354
355#endif // EGL_TRACE
356