Revert "Remove GLTrace support"

This reverts commit 5bf6f3b5bf06e04a742bde8d40409d3c9e434c05.

Change-Id: I25a2d9b4a4b219cb76b405db1f68997519361cd6
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 0f58f96..8df9af3 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -28,6 +28,8 @@
 
 #include <EGL/egl.h>
 
+#include "../glestrace.h"
+
 #include "egldefs.h"
 #include "Loader.h"
 
@@ -156,6 +158,7 @@
 }
 
 Loader::~Loader() {
+    GLTrace_stop();
 }
 
 static void* load_wrapper(const char* path) {
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 18cf261..4e0e5bc 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -32,6 +32,7 @@
 #include <utils/String8.h>
 
 #include "../egl_impl.h"
+#include "../glestrace.h"
 
 #include "egl_tls.h"
 #include "egldefs.h"
@@ -53,10 +54,161 @@
 
 // ----------------------------------------------------------------------------
 
+#if EGL_TRACE
+
+EGLAPI pthread_key_t gGLTraceKey = -1;
+
+// ----------------------------------------------------------------------------
+
+/**
+ * There are three different tracing methods:
+ * 1. libs/EGL/trace.cpp: Traces all functions to systrace.
+ *    To enable:
+ *      - set system property "debug.egl.trace" to "systrace" to trace all apps.
+ * 2. libs/EGL/trace.cpp: Logs a stack trace for GL errors after each function call.
+ *    To enable:
+ *      - set system property "debug.egl.trace" to "error" to trace all apps.
+ * 3. libs/EGL/trace.cpp: Traces all functions to logcat.
+ *    To enable:
+ *      - set system property "debug.egl.trace" to 1 to trace all apps.
+ *      - or call setGLTraceLevel(1) from an app to enable tracing for that app.
+ * 4. libs/GLES_trace: Traces all functions via protobuf to host.
+ *    To enable:
+ *        - set system property "debug.egl.debug_proc" to the application name.
+ *      - or call setGLDebugLevel(1) from the app.
+ */
+static int sEGLTraceLevel;
+static int sEGLApplicationTraceLevel;
+
+static bool sEGLSystraceEnabled;
+static bool sEGLGetErrorEnabled;
+
+static volatile int sEGLDebugLevel;
+
+extern gl_hooks_t gHooksTrace;
+extern gl_hooks_t gHooksSystrace;
+extern gl_hooks_t gHooksErrorTrace;
+
+int getEGLDebugLevel() {
+    return sEGLDebugLevel;
+}
+
+void setEGLDebugLevel(int level) {
+    sEGLDebugLevel = level;
+}
+
+static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) {
+    pthread_setspecific(gGLTraceKey, value);
+}
+
+gl_hooks_t const* getGLTraceThreadSpecific() {
+    return static_cast<gl_hooks_t*>(pthread_getspecific(gGLTraceKey));
+}
+
+void initEglTraceLevel() {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.egl.trace", value, "0");
+
+    sEGLGetErrorEnabled = !strcasecmp(value, "error");
+    if (sEGLGetErrorEnabled) {
+        sEGLSystraceEnabled = false;
+        sEGLTraceLevel = 0;
+        return;
+    }
+
+    sEGLSystraceEnabled = !strcasecmp(value, "systrace");
+    if (sEGLSystraceEnabled) {
+        sEGLTraceLevel = 0;
+        return;
+    }
+
+    int propertyLevel = atoi(value);
+    int applicationLevel = sEGLApplicationTraceLevel;
+    sEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
+}
+
+void initEglDebugLevel() {
+    if (getEGLDebugLevel() == 0) {
+        char value[PROPERTY_VALUE_MAX];
+
+        // check system property only on userdebug or eng builds
+        property_get("ro.debuggable", value, "0");
+        if (value[0] == '0')
+            return;
+
+        property_get("debug.egl.debug_proc", value, "");
+        if (strlen(value) > 0) {
+            FILE * file = fopen("/proc/self/cmdline", "r");
+            if (file) {
+                char cmdline[256];
+                if (fgets(cmdline, sizeof(cmdline), file)) {
+                    if (!strncmp(value, cmdline, strlen(value))) {
+                        // set EGL debug if the "debug.egl.debug_proc" property
+                        // matches the prefix of this application's command line
+                        setEGLDebugLevel(1);
+                    }
+                }
+                fclose(file);
+            }
+        }
+    }
+
+    if (getEGLDebugLevel() > 0) {
+        if (GLTrace_start() < 0) {
+            ALOGE("Error starting Tracer for OpenGL ES. Disabling..");
+            setEGLDebugLevel(0);
+        }
+    }
+}
+
+void setGLHooksThreadSpecific(gl_hooks_t const *value) {
+    if (sEGLGetErrorEnabled) {
+        setGlTraceThreadSpecific(value);
+        setGlThreadSpecific(&gHooksErrorTrace);
+    } else if (sEGLSystraceEnabled) {
+        setGlTraceThreadSpecific(value);
+        setGlThreadSpecific(&gHooksSystrace);
+    } else if (sEGLTraceLevel > 0) {
+        setGlTraceThreadSpecific(value);
+        setGlThreadSpecific(&gHooksTrace);
+    } else if (getEGLDebugLevel() > 0 && value != &gHooksNoContext) {
+        setGlTraceThreadSpecific(value);
+        setGlThreadSpecific(GLTrace_getGLHooks());
+    } else {
+        setGlTraceThreadSpecific(NULL);
+        setGlThreadSpecific(value);
+    }
+}
+
+/*
+ * Global entry point to allow applications to modify their own trace level.
+ * The effective trace level is the max of this level and the value of debug.egl.trace.
+ */
+extern "C"
+void setGLTraceLevel(int level) {
+    sEGLApplicationTraceLevel = level;
+}
+
+/*
+ * Global entry point to allow applications to modify their own debug level.
+ * Debugging is enabled if either the application requested it, or if the system property
+ * matches the application's name.
+ * Note that this only sets the debug level. The value is read and used either in
+ * initEglDebugLevel() if the application hasn't initialized its display yet, or when
+ * eglSwapBuffers() is called next.
+ */
+void EGLAPI setGLDebugLevel(int level) {
+    setEGLDebugLevel(level);
+}
+
+#else
+
 void setGLHooksThreadSpecific(gl_hooks_t const *value) {
     setGlThreadSpecific(value);
 }
 
+#endif
+
 /*****************************************************************************/
 
 static int gl_no_context() {
@@ -79,6 +231,10 @@
 
 static void early_egl_init(void)
 {
+#if EGL_TRACE
+    pthread_key_create(&gGLTraceKey, NULL);
+    initEglTraceLevel();
+#endif
     int numHooks = sizeof(gHooksNoContext) / sizeof(EGLFuncPointer);
     EGLFuncPointer *iter = reinterpret_cast<EGLFuncPointer*>(&gHooksNoContext);
     for (int hook = 0; hook < numHooks; ++hook) {
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 7c905ae..8378907 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -39,6 +39,7 @@
 #include <utils/Trace.h>
 
 #include "../egl_impl.h"
+#include "../glestrace.h"
 #include "../hooks.h"
 
 #include "egl_display.h"
@@ -230,6 +231,8 @@
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 extern EGLBoolean egl_init_drivers();
 extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
+extern int getEGLDebugLevel();
+extern void setEGLDebugLevel(int level);
 extern gl_hooks_t gHooksTrace;
 
 } // namespace android;
@@ -680,6 +683,10 @@
             }
             egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
                     version);
+#if EGL_TRACE
+            if (getEGLDebugLevel() > 0)
+                GLTrace_eglCreateContext(version, c);
+#endif
             return c;
         }
     }
@@ -785,6 +792,10 @@
         if (c) {
             setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
             egl_tls_t::setContext(ctx);
+#if EGL_TRACE
+            if (getEGLDebugLevel() > 0)
+                GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
+#endif
             _c.acquire();
             _r.acquire();
             _d.acquire();
@@ -969,6 +980,10 @@
                 "no more slots for eglGetProcAddress(\"%s\")",
                 procname);
 
+#if EGL_TRACE
+        gl_hooks_t *debugHooks = GLTrace_getGLHooks();
+#endif
+
         if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
             bool found = false;
 
@@ -978,6 +993,10 @@
                 addr =
                 cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
                 cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
+#if EGL_TRACE
+                debugHooks->ext.extensions[slot] =
+                gHooksTrace.ext.extensions[slot] =
+#endif
                         cnx->egl.eglGetProcAddress(procname);
                 if (addr) found = true;
             }
@@ -1069,6 +1088,34 @@
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
+#if EGL_TRACE
+    gl_hooks_t const *trace_hooks = getGLTraceThreadSpecific();
+    if (getEGLDebugLevel() > 0) {
+        if (trace_hooks == NULL) {
+            if (GLTrace_start() < 0) {
+                ALOGE("Disabling Tracer for OpenGL ES");
+                setEGLDebugLevel(0);
+            } else {
+                // switch over to the trace version of hooks
+                EGLContext ctx = egl_tls_t::getContext();
+                egl_context_t * const c = get_context(ctx);
+                if (c) {
+                    setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
+                    GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
+                }
+            }
+        }
+
+        GLTrace_eglSwapBuffers(dpy, draw);
+    } else if (trace_hooks != NULL) {
+        // tracing is now disabled, so switch back to the non trace version
+        EGLContext ctx = egl_tls_t::getContext();
+        egl_context_t * const c = get_context(ctx);
+        if (c) setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
+        GLTrace_stop();
+    }
+#endif
+
     egl_surface_t const * const s = get_surface(draw);
 
     if (CC_UNLIKELY(dp->traceGpuCompletion)) {
@@ -1318,6 +1365,11 @@
 {
     clearError();
 
+#if EGL_TRACE
+    if (getEGLDebugLevel() > 0)
+        GLTrace_eglReleaseThread();
+#endif
+
     // If there is context bound to the thread, release it
     egl_display_t::loseCurrent(get_context(getContext()));
 
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 67edcf3..ec59235 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -38,6 +38,8 @@
 extern char const * const gBuiltinExtensionString;
 extern char const * const gExtensionString;
 
+extern void initEglTraceLevel();
+extern void initEglDebugLevel();
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 
 // ----------------------------------------------------------------------------
@@ -137,6 +139,15 @@
     {
         Mutex::Autolock _l(lock);
 
+#if EGL_TRACE
+
+        // Called both at early_init time and at this time. (Early_init is pre-zygote, so
+        // the information from that call may be stale.)
+        initEglTraceLevel();
+        initEglDebugLevel();
+
+#endif
+
         setGLHooksThreadSpecific(&gHooksNoContext);
 
         // initialize each EGL and
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
index 00eae0b..5af4f5b 100644
--- a/opengl/libs/EGL/egl_tls.h
+++ b/opengl/libs/EGL/egl_tls.h
@@ -68,6 +68,14 @@
     egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r, true)
 
 // ----------------------------------------------------------------------------
+
+#if EGL_TRACE
+
+extern gl_hooks_t const* getGLTraceThreadSpecific();
+
+#endif
+
+// ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
 
diff --git a/opengl/libs/EGL/trace.cpp b/opengl/libs/EGL/trace.cpp
new file mode 100644
index 0000000..4f07053
--- /dev/null
+++ b/opengl/libs/EGL/trace.cpp
@@ -0,0 +1,463 @@
+/*
+ ** Copyright 2010, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#if EGL_TRACE
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <cutils/log.h>
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Trace.h>
+
+#include <utils/CallStack.h>
+
+#include "egl_tls.h"
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct GLenumString {
+    // The GL_TIMEOUT_IGNORED "enum" doesn't fit in a GLenum, so use GLuint64
+    GLuint64 e;
+    const char* s;
+};
+
+#undef GL_ENUM
+#define GL_ENUM(VAL,NAME) {VAL, #NAME},
+
+static GLenumString g_enumnames[] = {
+#include "enums.in"
+};
+#undef GL_ENUM
+
+static int compareGLEnum(const void* a, const void* b) {
+    return ((const GLenumString*) a)->e - ((const GLenumString*) b)->e;
+}
+
+static const char* GLEnumToString(GLenum e) {
+    GLenumString key = {e, ""};
+    const GLenumString* result = (const GLenumString*) bsearch(
+        &key, g_enumnames,
+        sizeof(g_enumnames) / sizeof(g_enumnames[0]),
+        sizeof(g_enumnames[0]), compareGLEnum);
+    if (result) {
+        return result->s;
+    }
+    return NULL;
+}
+
+static const char* GLbooleanToString(GLboolean arg) {
+    return arg ? "GL_TRUE" : "GL_FALSE";
+}
+
+static GLenumString g_bitfieldNames[] = {
+    {0x00004000, "GL_COLOR_BUFFER_BIT"},
+    {0x00000400, "GL_STENCIL_BUFFER_BIT"},
+    {0x00000100, "GL_DEPTH_BUFFER_BIT"}
+};
+
+class StringBuilder {
+    static const int lineSize = 500;
+    char line[lineSize];
+    int line_index;
+public:
+    StringBuilder() {
+        line_index = 0;
+        line[0] = '\0';
+    }
+    void append(const char* fmt, ...) {
+        va_list argp;
+        va_start(argp, fmt);
+        line_index += vsnprintf(line + line_index, lineSize-line_index, fmt, argp);
+        va_end(argp);
+    }
+    const char* getString() {
+        line_index = 0;
+        line[lineSize-1] = '\0';
+        return line;
+    }
+};
+
+
+static void TraceGLShaderSource(GLuint shader, GLsizei count,
+    const GLchar** string, const GLint* length) {
+    ALOGD("const char* shaderSrc[] = {");
+    for (GLsizei i = 0; i < count; i++) {
+        const char* comma = i < count-1 ? "," : "";
+        const GLchar* s = string[i];
+        if (length) {
+            GLint len = length[i];
+            ALOGD("    \"%*s\"%s", len, s, comma);
+        } else {
+            ALOGD("    \"%s\"%s", s, comma);
+        }
+    }
+    ALOGD("};");
+    if (length) {
+        ALOGD("const GLint* shaderLength[] = {");
+        for (GLsizei i = 0; i < count; i++) {
+            const char* comma = i < count-1 ? "," : "";
+            GLint len = length[i];
+            ALOGD("    \"%d\"%s", len, comma);
+        }
+        ALOGD("};");
+        ALOGD("glShaderSource(%u, %u, shaderSrc, shaderLength);",
+            shader, count);
+    } else {
+        ALOGD("glShaderSource(%u, %u, shaderSrc, (const GLint*) 0);",
+            shader, count);
+    }
+}
+
+static void TraceValue(int elementCount, char type,
+        GLsizei chunkCount, GLsizei chunkSize, const void* value) {
+    StringBuilder stringBuilder;
+    GLsizei count = chunkCount * chunkSize;
+    bool isFloat = type == 'f';
+    const char* typeString = isFloat ? "GLfloat" : "GLint";
+    ALOGD("const %s value[] = {", typeString);
+    for (GLsizei i = 0; i < count; i++) {
+        StringBuilder builder;
+        builder.append("    ");
+        for (int e = 0; e < elementCount; e++) {
+            const char* comma = ", ";
+            if (e == elementCount-1) {
+                if (i == count - 1) {
+                    comma = "";
+                } else {
+                    comma = ",";
+                }
+            }
+            if (isFloat) {
+                builder.append("%g%s", * (GLfloat*) value, comma);
+                value = (void*) (((GLfloat*) value) + 1);
+            } else {
+                builder.append("%d%s", * (GLint*) value, comma);
+                value = (void*) (((GLint*) value) + 1);
+            }
+        }
+        ALOGD("%s", builder.getString());
+        if (chunkSize > 1 && i < count-1
+                && (i % chunkSize) == (chunkSize-1)) {
+            ALOGD("%s", ""); // Print a blank line.
+        }
+    }
+    ALOGD("};");
+}
+
+static void TraceUniformv(int elementCount, char type,
+        GLuint location, GLsizei count, const void* value) {
+    TraceValue(elementCount, type, count, 1, value);
+    ALOGD("glUniform%d%c(%u, %u, value);", elementCount, type, location, count);
+}
+
+static void TraceUniformMatrix(int matrixSideLength,
+        GLuint location, GLsizei count, GLboolean transpose, const void* value) {
+    TraceValue(matrixSideLength, 'f', count, matrixSideLength, value);
+    ALOGD("glUniformMatrix%dfv(%u, %u, %s, value);", matrixSideLength, location, count,
+            GLbooleanToString(transpose));
+}
+
+static void TraceGL(const char* name, int numArgs, ...) {
+    va_list argp;
+    va_start(argp, numArgs);
+    int nameLen = strlen(name);
+
+    // glShaderSource
+    if (nameLen == 14 && strcmp(name, "glShaderSource") == 0) {
+        va_arg(argp, const char*);
+        GLuint shader = va_arg(argp, GLuint);
+        va_arg(argp, const char*);
+        GLsizei count = va_arg(argp, GLsizei);
+        va_arg(argp, const char*);
+        const GLchar** string = (const GLchar**) va_arg(argp, void*);
+        va_arg(argp, const char*);
+        const GLint* length = (const GLint*) va_arg(argp, void*);
+        va_end(argp);
+        TraceGLShaderSource(shader, count, string, length);
+        return;
+    }
+
+    // glUniformXXv
+
+    if (nameLen == 12 && strncmp(name, "glUniform", 9) == 0 && name[11] == 'v') {
+        int elementCount = name[9] - '0'; // 1..4
+        char type = name[10]; // 'f' or 'i'
+        va_arg(argp, const char*);
+        GLuint location = va_arg(argp, GLuint);
+        va_arg(argp, const char*);
+        GLsizei count = va_arg(argp, GLsizei);
+        va_arg(argp, const char*);
+        const void* value = (const void*) va_arg(argp, void*);
+        va_end(argp);
+        TraceUniformv(elementCount, type, location, count, value);
+        return;
+    }
+
+    // glUniformMatrixXfv
+
+    if (nameLen == 18 && strncmp(name, "glUniformMatrix", 15) == 0
+            && name[16] == 'f' && name[17] == 'v') {
+        int matrixSideLength = name[15] - '0'; // 2..4
+        va_arg(argp, const char*);
+        GLuint location = va_arg(argp, GLuint);
+        va_arg(argp, const char*);
+        GLsizei count = va_arg(argp, GLsizei);
+        va_arg(argp, const char*);
+        GLboolean transpose = (GLboolean) va_arg(argp, int);
+        va_arg(argp, const char*);
+        const void* value = (const void*) va_arg(argp, void*);
+        va_end(argp);
+        TraceUniformMatrix(matrixSideLength, location, count, transpose, value);
+        return;
+    }
+
+    StringBuilder builder;
+    builder.append("%s(", name);
+    for (int i = 0; i < numArgs; i++) {
+        if (i > 0) {
+            builder.append(", ");
+        }
+        const char* type = va_arg(argp, const char*);
+        bool isPtr = type[strlen(type)-1] == '*'
+            || strcmp(type, "GLeglImageOES") == 0;
+        if (isPtr) {
+            const void* arg = va_arg(argp, const void*);
+            builder.append("(%s) 0x%08x", type, (size_t) arg);
+        } else if (strcmp(type, "GLbitfield") == 0) {
+            size_t arg = va_arg(argp, size_t);
+            bool first = true;
+            for (size_t i = 0; i < sizeof(g_bitfieldNames) / sizeof(g_bitfieldNames[0]); i++) {
+                const GLenumString* b = &g_bitfieldNames[i];
+                if (b->e & arg) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        builder.append(" | ");
+                    }
+                    builder.append("%s", b->s);
+                    arg &= ~b->e;
+                }
+            }
+            if (first || arg != 0) {
+                if (!first) {
+                    builder.append(" | ");
+                }
+                builder.append("0x%08x", arg);
+            }
+        } else if (strcmp(type, "GLboolean") == 0) {
+            GLboolean arg = va_arg(argp, int);
+            builder.append("%s", GLbooleanToString(arg));
+        } else if (strcmp(type, "GLclampf") == 0) {
+            double arg = va_arg(argp, double);
+            builder.append("%g", arg);
+        } else if (strcmp(type, "GLenum") == 0) {
+            GLenum arg = va_arg(argp, int);
+            const char* s = GLEnumToString(arg);
+            if (s) {
+                builder.append("%s", s);
+            } else {
+                builder.append("0x%x", arg);
+            }
+        } else if (strcmp(type, "GLfixed") == 0) {
+            int arg = va_arg(argp, int);
+            builder.append("0x%08x", arg);
+        } else if (strcmp(type, "GLfloat") == 0) {
+            double arg = va_arg(argp, double);
+            builder.append("%g", arg);
+        } else if (strcmp(type, "GLint") == 0) {
+            int arg = va_arg(argp, int);
+            const char* s = NULL;
+            if (strcmp(name, "glTexParameteri") == 0) {
+                s = GLEnumToString(arg);
+            }
+            if (s) {
+                builder.append("%s", s);
+            } else {
+                builder.append("%d", arg);
+            }
+        } else if (strcmp(type, "GLintptr") == 0) {
+            int arg = va_arg(argp, unsigned int);
+            builder.append("%u", arg);
+        } else if (strcmp(type, "GLsizei") == 0) {
+            int arg = va_arg(argp, size_t);
+            builder.append("%u", arg);
+        } else if (strcmp(type, "GLsizeiptr") == 0) {
+            int arg = va_arg(argp, size_t);
+            builder.append("%u", arg);
+        } else if (strcmp(type, "GLuint") == 0) {
+            int arg = va_arg(argp, unsigned int);
+            builder.append("%u", arg);
+        } else {
+            builder.append("/* ??? %s */", type);
+            break;
+        }
+    }
+    builder.append(");");
+    ALOGD("%s", builder.getString());
+    va_end(argp);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Log trace
+///////////////////////////////////////////////////////////////////////////
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+#define TRACE_GL_VOID(_api, _args, _argList, ...)                         \
+static void Tracing_ ## _api _args {                                      \
+    TraceGL(#_api, __VA_ARGS__);                                          \
+    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
+    _c->_api _argList;                                                    \
+}
+
+#define TRACE_GL(_type, _api, _args, _argList, ...)                       \
+static _type Tracing_ ## _api _args {                                     \
+    TraceGL(#_api, __VA_ARGS__);                                        \
+    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
+    return _c->_api _argList;                                             \
+}
+
+extern "C" {
+#include "../trace.in"
+}
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+#define GL_ENTRY(_r, _api, ...) Tracing_ ## _api,
+EGLAPI gl_hooks_t gHooksTrace = {
+    {
+        #include "entries.in"
+    },
+    {
+        {0}
+    }
+};
+#undef GL_ENTRY
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+///////////////////////////////////////////////////////////////////////////
+// Systrace
+///////////////////////////////////////////////////////////////////////////
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+#define TRACE_GL_VOID(_api, _args, _argList, ...)                         \
+static void Systrace_ ## _api _args {                                     \
+    ATRACE_NAME(#_api);                                                   \
+    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
+    _c->_api _argList;                                                    \
+}
+
+#define TRACE_GL(_type, _api, _args, _argList, ...)                       \
+static _type Systrace_ ## _api _args {                                    \
+    ATRACE_NAME(#_api);                                                   \
+    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
+    return _c->_api _argList;                                             \
+}
+
+extern "C" {
+#include "../trace.in"
+}
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+#define GL_ENTRY(_r, _api, ...) Systrace_ ## _api,
+EGLAPI gl_hooks_t gHooksSystrace = {
+    {
+        #include "entries.in"
+    },
+    {
+        {0}
+    }
+};
+#undef GL_ENTRY
+
+///////////////////////////////////////////////////////////////////////////
+//
+///////////////////////////////////////////////////////////////////////////
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+#define CHECK_ERROR(_c, _api)                                             \
+    GLenum status = GL_NO_ERROR;                                          \
+    bool error = false;                                                   \
+    while ((status = _c->glGetError()) != GL_NO_ERROR) {                  \
+        ALOGD("[" #_api "] 0x%x", status);                                \
+        error = true;                                                     \
+    }                                                                     \
+    if (error) {                                                          \
+        CallStack s;                                                      \
+        s.update();                                                       \
+        s.log("glGetError:" #_api);                                       \
+    }                                                                     \
+
+#define TRACE_GL_VOID(_api, _args, _argList, ...)                         \
+static void ErrorTrace_ ## _api _args {                                   \
+    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
+    _c->_api _argList;                                                    \
+    CHECK_ERROR(_c, _api);                                                \
+}
+
+#define TRACE_GL(_type, _api, _args, _argList, ...)                       \
+static _type ErrorTrace_ ## _api _args {                                  \
+    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
+    _type _r = _c->_api _argList;                                         \
+    CHECK_ERROR(_c, _api);                                                \
+    return _r;                                                            \
+}
+
+extern "C" {
+#include "../trace.in"
+}
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+#define GL_ENTRY(_r, _api, ...) ErrorTrace_ ## _api,
+EGLAPI gl_hooks_t gHooksErrorTrace = {
+    {
+        #include "entries.in"
+    },
+    {
+        {0}
+    }
+};
+#undef GL_ENTRY
+#undef CHECK_ERROR
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif // EGL_TRACE