From 16928bfeca8858a0acae6942fc68c14a040b92ff Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Thu, 18 Oct 2012 16:16:10 -0700 Subject: [PATCH] Add runtime debugging capabilities to OpenGL The shell property debug.egl.trace can now be set to: 0 disables tracing 1 logs all GL calls error checks glGetError after every GL call, logs a stack trace on error systrace logs each GL call to systrace Change-Id: I34a2a2d4e19c373fd9eaa1b0cd93e67c87378996 --- include/utils/Trace.h | 5 ++ opengl/libs/EGL/egl.cpp | 39 +++++++++++++-- opengl/libs/EGL/trace.cpp | 103 +++++++++++++++++++++++++++++++++++++- opengl/libs/GLES2/gl2.cpp | 37 -------------- 4 files changed, 142 insertions(+), 42 deletions(-) diff --git a/include/utils/Trace.h b/include/utils/Trace.h index e5cc7ec30..93e228546 100644 --- a/include/utils/Trace.h +++ b/include/utils/Trace.h @@ -67,6 +67,11 @@ // function body. #define ATRACE_CALL() android::ScopedTrace ___tracer(ATRACE_TAG, __FUNCTION__) +// ATRACE_NAME traces the beginning and end of the current function. To trace +// the correct start and end times this macro should be the first line of the +// function body. +#define ATRACE_NAME(name) android::ScopedTrace ___tracer(ATRACE_TAG, name) + // ATRACE_INT traces a named integer value. This can be used to track how the // value changes over time in a trace. #define ATRACE_INT(name, value) android::Tracer::traceCounter(ATRACE_TAG, name, value) diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 7ca210c2f..96e1cbacf 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -62,12 +62,18 @@ EGLAPI pthread_key_t gGLTraceKey = -1; // ---------------------------------------------------------------------------- /** - * There are two different tracing methods: - * 1. libs/EGL/trace.cpp: Traces all functions to logcat. + * 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. - * 2. libs/GLES_trace: Traces all functions via protobuf to host. + * 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. @@ -75,10 +81,15 @@ EGLAPI pthread_key_t gGLTraceKey = -1; static int sEGLTraceLevel; static int sEGLApplicationTraceLevel; +static bool sEGLSystraceEnabled; +static bool sEGLGetErrorEnabled; + int gEGLDebugLevel; static int sEGLApplicationDebugLevel; extern gl_hooks_t gHooksTrace; +extern gl_hooks_t gHooksSystrace; +extern gl_hooks_t gHooksErrorTrace; static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) { pthread_setspecific(gGLTraceKey, value); @@ -91,6 +102,20 @@ gl_hooks_t const* getGLTraceThreadSpecific() { 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; @@ -125,7 +150,13 @@ void initEglDebugLevel() { } void setGLHooksThreadSpecific(gl_hooks_t const *value) { - if (sEGLTraceLevel > 0) { + if (sEGLGetErrorEnabled) { + setGlTraceThreadSpecific(value); + setGlThreadSpecific(&gHooksErrorTrace); + } else if (sEGLSystraceEnabled) { + setGlTraceThreadSpecific(value); + setGlThreadSpecific(&gHooksSystrace); + } else if (sEGLTraceLevel > 0) { setGlTraceThreadSpecific(value); setGlThreadSpecific(&gHooksTrace); } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) { diff --git a/opengl/libs/EGL/trace.cpp b/opengl/libs/EGL/trace.cpp index 52907c1f1..a51b086e4 100644 --- a/opengl/libs/EGL/trace.cpp +++ b/opengl/libs/EGL/trace.cpp @@ -26,6 +26,11 @@ #include +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include + +#include + #include "egl_tls.h" #include "hooks.h" @@ -314,6 +319,10 @@ static void TraceGL(const char* name, int numArgs, ...) { va_end(argp); } +/////////////////////////////////////////////////////////////////////////// +// Log trace +/////////////////////////////////////////////////////////////////////////// + #undef TRACE_GL_VOID #undef TRACE_GL @@ -349,7 +358,6 @@ EGLAPI gl_hooks_t gHooksTrace = { }; #undef GL_ENTRY - #undef TRACE_GL_VOID #undef TRACE_GL @@ -372,6 +380,99 @@ extern "C" { #include "../debug.in" } +/////////////////////////////////////////////////////////////////////////// +// 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.dump("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 diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp index 2d0045e05..55ef499e2 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -26,11 +26,6 @@ #include #include -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include - -#include - #include "hooks.h" #include "egl_impl.h" @@ -44,10 +39,6 @@ using namespace android; #undef CALL_GL_API #undef CALL_GL_API_RETURN -#define DEBUG_CALL_GL_API 0 -#define DEBUG_PRINT_CALL_STACK_ON_ERROR 0 -#define SYSTRACE_CALL_GL_API 0 - #if USE_FAST_TLS_KEY #ifdef HAVE_ARM_TLS_REGISTER @@ -83,38 +74,10 @@ using namespace android; #define API_ENTRY(_api) _api -#if DEBUG_CALL_GL_API - - #define CALL_GL_API(_api, ...) \ - gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ - _c->_api(__VA_ARGS__); \ - GLenum status = GL_NO_ERROR; \ - bool error = false; \ - while ((status = glGetError()) != GL_NO_ERROR) { \ - ALOGD("[" #_api "] 0x%x", status); \ - error = true; \ - } \ - if (DEBUG_PRINT_CALL_STACK_ON_ERROR && error) { \ - CallStack s; \ - s.update(); \ - s.dump("glGetError:" #_api); \ - } - -#elif SYSTRACE_CALL_GL_API - - #define CALL_GL_API(_api, ...) \ - ATRACE_CALL(); \ - gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ - _c->_api(__VA_ARGS__); - -#else - #define CALL_GL_API(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ _c->_api(__VA_ARGS__); -#endif - #define CALL_GL_API_RETURN(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ return _c->_api(__VA_ARGS__)