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