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