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