Loading opengl/libs/EGL/egl.cpp +39 −28 Original line number Diff line number Diff line Loading @@ -84,13 +84,20 @@ static int sEGLApplicationTraceLevel; static bool sEGLSystraceEnabled; static bool sEGLGetErrorEnabled; int gEGLDebugLevel; static int sEGLApplicationDebugLevel; 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); } Loading Loading @@ -122,7 +129,7 @@ void initEglTraceLevel() { } void initEglDebugLevel() { int propertyLevel = 0; if (getEGLDebugLevel() == 0) { char value[PROPERTY_VALUE_MAX]; // check system property only on userdebug or eng builds Loading @@ -132,26 +139,26 @@ void initEglDebugLevel() { property_get("debug.egl.debug_proc", value, ""); if (strlen(value) > 0) { long pid = getpid(); char procPath[128] = {}; sprintf(procPath, "/proc/%ld/cmdline", pid); FILE * file = fopen(procPath, "r"); FILE * file = fopen("/proc/self/cmdline", "r"); if (file) { char cmdline[256] = {}; if (fgets(cmdline, sizeof(cmdline) - 1, 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 propertyLevel = 1; setEGLDebugLevel(1); } } fclose(file); } } } gEGLDebugLevel = propertyLevel || sEGLApplicationDebugLevel; if (gEGLDebugLevel > 0) { GLTrace_start(); if (getEGLDebugLevel() > 0) { if (GLTrace_start() < 0) { ALOGE("Error starting Tracer for OpenGL ES. Disabling.."); setEGLDebugLevel(0); } } } Loading @@ -165,10 +172,11 @@ void setGLHooksThreadSpecific(gl_hooks_t const *value) { } else if (sEGLTraceLevel > 0) { setGlTraceThreadSpecific(value); setGlThreadSpecific(&gHooksTrace); } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) { } else if (getEGLDebugLevel() > 0 && value != &gHooksNoContext) { setGlTraceThreadSpecific(value); setGlThreadSpecific(GLTrace_getGLHooks()); } else { setGlTraceThreadSpecific(NULL); setGlThreadSpecific(value); } } Loading @@ -186,9 +194,12 @@ void setGLTraceLevel(int 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) { sEGLApplicationDebugLevel = level; setEGLDebugLevel(level); } #else Loading opengl/libs/EGL/eglApi.cpp +29 −5 Original line number Diff line number Diff line Loading @@ -97,7 +97,8 @@ namespace android { extern void setGLHooksThreadSpecific(gl_hooks_t const *value); extern EGLBoolean egl_init_drivers(); extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS]; extern int gEGLDebugLevel; extern int getEGLDebugLevel(); extern void setEGLDebugLevel(int level); extern gl_hooks_t gHooksTrace; } // namespace android; Loading Loading @@ -465,7 +466,7 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version); #if EGL_TRACE if (gEGLDebugLevel > 0) if (getEGLDebugLevel() > 0) GLTrace_eglCreateContext(version, c); #endif return c; Loading Loading @@ -578,7 +579,7 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, setGLHooksThreadSpecific(c->cnx->hooks[c->version]); egl_tls_t::setContext(ctx); #if EGL_TRACE if (gEGLDebugLevel > 0) if (getEGLDebugLevel() > 0) GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx); #endif _c.acquire(); Loading Loading @@ -858,8 +859,31 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) return setError(EGL_BAD_SURFACE, EGL_FALSE); #if EGL_TRACE if (gEGLDebugLevel > 0) 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); Loading Loading @@ -1078,7 +1102,7 @@ EGLBoolean eglReleaseThread(void) egl_tls_t::clearTLS(); #if EGL_TRACE if (gEGLDebugLevel > 0) if (getEGLDebugLevel() > 0) GLTrace_eglReleaseThread(); #endif return EGL_TRUE; Loading opengl/libs/GLES_trace/DESIGN.txt +31 −3 Original line number Diff line number Diff line Loading @@ -9,9 +9,6 @@ Code Runtime Behavior: control whether tracing should be enabled for a certain process. If tracing is enabled, this calls GLTrace_start() to start the trace server. Note that initEglTraceLevel() is also called from early_egl_init(), but that happens in the context of the zygote, so that invocation has no effect. egl_display_t::initialize() then calls setGLHooksThreadSpecific() where we set the thread specific gl_hooks structure to point to the trace implementation. From this point on, every GLES call is redirected to the trace implementation. Loading @@ -30,6 +27,37 @@ Code Runtime Behavior: to explore if a more graceful method of stopping the application, or detaching tracing from the application is required. Enabling tracing while the application is running: In order to allow tracing of an already running application, we allow DdmServer to enable OpenGL tracing. In such a case, the application already has its GL hooks set up to point to the real GL implementation, and we need to switch them to point to the trace implementation. This is achieved by checking whether tracing should be enabled at every eglSwap call. (Note: We were already checking for tracing at every eglSwap, the only change now is that the tracing could actually be ON/OFF at runtime - earlier it was set once and never changed). If eglSwap detects that tracing should be enabled now, then it performs the following steps: - switch the gl hooks to point to the trace implementation. - call trace eglMakeCurrent to indicate that there is now a new context that is current. - continue on with tracing the eglSwap call. This switches the hooks to point to the trace implementation only for the current context. But the other contexts have their gl hooks updated when they perform eglMakeCurrent. The GLTrace version of eglMakeCurrent now has to be updated to allow switching to a context it may not know of. In such a case, it creates a context matching the version that it is now switching to. Disabling tracing: We disable tracing under two conditions: - stop tracing request from DdmServer - gltrace transport gets disconnected from the host. In either case, both actions simply disable the tracing flag. The current context gets its gl hooks restored in the next eglSwap, and the other traced contexts get their gl hooks restored when they perform a eglMakeCurrent. Code Structure: glestrace.h declares all the hooks exposed by libglestrace. These are used by EGL/egl.cpp and Loading opengl/libs/GLES_trace/src/gltrace_eglapi.cpp +57 −10 Original line number Diff line number Diff line Loading @@ -33,6 +33,9 @@ using gltrace::GLTraceState; using gltrace::GLTraceContext; using gltrace::TCPStream; static pthread_mutex_t sGlTraceStateLock = PTHREAD_MUTEX_INITIALIZER; static int sGlTraceInProgress; static GLTraceState *sGLTraceState; static pthread_t sReceiveThreadId; Loading Loading @@ -105,33 +108,66 @@ static void *commandReceiveTask(void *arg) { return NULL; } void GLTrace_start() { char udsName[PROPERTY_VALUE_MAX]; /** * Starts Trace Server and waits for connection from the host. * Returns -1 in case of connection error, 0 otherwise. */ int GLTrace_start() { int status = 0; int clientSocket = -1; TCPStream *stream = NULL; pthread_mutex_lock(&sGlTraceStateLock); if (sGlTraceInProgress) { goto done; } char udsName[PROPERTY_VALUE_MAX]; property_get("debug.egl.debug_portname", udsName, "gltrace"); int clientSocket = gltrace::acceptClientConnection(udsName); clientSocket = gltrace::acceptClientConnection(udsName); if (clientSocket < 0) { ALOGE("Error creating GLTrace server socket. Quitting application."); exit(-1); ALOGE("Error creating GLTrace server socket. Tracing disabled."); status = -1; goto done; } sGlTraceInProgress = 1; // create communication channel to the host TCPStream *stream = new TCPStream(clientSocket); stream = new TCPStream(clientSocket); // initialize tracing state sGLTraceState = new GLTraceState(stream); pthread_create(&sReceiveThreadId, NULL, commandReceiveTask, sGLTraceState); done: pthread_mutex_unlock(&sGlTraceStateLock); return status; } void GLTrace_stop() { pthread_mutex_lock(&sGlTraceStateLock); if (sGlTraceInProgress) { sGlTraceInProgress = 0; delete sGLTraceState; sGLTraceState = NULL; } pthread_mutex_unlock(&sGlTraceStateLock); } void GLTrace_eglCreateContext(int version, EGLContext c) { pthread_mutex_lock(&sGlTraceStateLock); GLTraceState *state = sGLTraceState; pthread_mutex_unlock(&sGlTraceStateLock); if (state == NULL) return; // update trace state for new EGL context GLTraceContext *traceContext = sGLTraceState->createTraceContext(version, c); GLTraceContext *traceContext = state->createTraceContext(version, c); gltrace::setupTraceContextThreadSpecific(traceContext); // trace command through to the host Loading @@ -139,8 +175,19 @@ void GLTrace_eglCreateContext(int version, EGLContext c) { } void GLTrace_eglMakeCurrent(const unsigned version, gl_hooks_t *hooks, EGLContext c) { pthread_mutex_lock(&sGlTraceStateLock); GLTraceState *state = sGLTraceState; pthread_mutex_unlock(&sGlTraceStateLock); if (state == NULL) return; // setup per context state GLTraceContext *traceContext = sGLTraceState->getTraceContext(c); GLTraceContext *traceContext = state->getTraceContext(c); if (traceContext == NULL) { GLTrace_eglCreateContext(version, c); traceContext = state->getTraceContext(c); } traceContext->hooks = hooks; gltrace::setupTraceContextThreadSpecific(traceContext); Loading opengl/libs/glestrace.h +1 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ void GLTrace_eglReleaseThread(); void GLTrace_eglSwapBuffers(void*, void*); /* Start and stop GL Tracing. */ void GLTrace_start(); int GLTrace_start(); void GLTrace_stop(); /* Obtain the gl_hooks structure filled with the trace implementation for all GL functions. */ Loading Loading
opengl/libs/EGL/egl.cpp +39 −28 Original line number Diff line number Diff line Loading @@ -84,13 +84,20 @@ static int sEGLApplicationTraceLevel; static bool sEGLSystraceEnabled; static bool sEGLGetErrorEnabled; int gEGLDebugLevel; static int sEGLApplicationDebugLevel; 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); } Loading Loading @@ -122,7 +129,7 @@ void initEglTraceLevel() { } void initEglDebugLevel() { int propertyLevel = 0; if (getEGLDebugLevel() == 0) { char value[PROPERTY_VALUE_MAX]; // check system property only on userdebug or eng builds Loading @@ -132,26 +139,26 @@ void initEglDebugLevel() { property_get("debug.egl.debug_proc", value, ""); if (strlen(value) > 0) { long pid = getpid(); char procPath[128] = {}; sprintf(procPath, "/proc/%ld/cmdline", pid); FILE * file = fopen(procPath, "r"); FILE * file = fopen("/proc/self/cmdline", "r"); if (file) { char cmdline[256] = {}; if (fgets(cmdline, sizeof(cmdline) - 1, 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 propertyLevel = 1; setEGLDebugLevel(1); } } fclose(file); } } } gEGLDebugLevel = propertyLevel || sEGLApplicationDebugLevel; if (gEGLDebugLevel > 0) { GLTrace_start(); if (getEGLDebugLevel() > 0) { if (GLTrace_start() < 0) { ALOGE("Error starting Tracer for OpenGL ES. Disabling.."); setEGLDebugLevel(0); } } } Loading @@ -165,10 +172,11 @@ void setGLHooksThreadSpecific(gl_hooks_t const *value) { } else if (sEGLTraceLevel > 0) { setGlTraceThreadSpecific(value); setGlThreadSpecific(&gHooksTrace); } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) { } else if (getEGLDebugLevel() > 0 && value != &gHooksNoContext) { setGlTraceThreadSpecific(value); setGlThreadSpecific(GLTrace_getGLHooks()); } else { setGlTraceThreadSpecific(NULL); setGlThreadSpecific(value); } } Loading @@ -186,9 +194,12 @@ void setGLTraceLevel(int 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) { sEGLApplicationDebugLevel = level; setEGLDebugLevel(level); } #else Loading
opengl/libs/EGL/eglApi.cpp +29 −5 Original line number Diff line number Diff line Loading @@ -97,7 +97,8 @@ namespace android { extern void setGLHooksThreadSpecific(gl_hooks_t const *value); extern EGLBoolean egl_init_drivers(); extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS]; extern int gEGLDebugLevel; extern int getEGLDebugLevel(); extern void setEGLDebugLevel(int level); extern gl_hooks_t gHooksTrace; } // namespace android; Loading Loading @@ -465,7 +466,7 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version); #if EGL_TRACE if (gEGLDebugLevel > 0) if (getEGLDebugLevel() > 0) GLTrace_eglCreateContext(version, c); #endif return c; Loading Loading @@ -578,7 +579,7 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, setGLHooksThreadSpecific(c->cnx->hooks[c->version]); egl_tls_t::setContext(ctx); #if EGL_TRACE if (gEGLDebugLevel > 0) if (getEGLDebugLevel() > 0) GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx); #endif _c.acquire(); Loading Loading @@ -858,8 +859,31 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) return setError(EGL_BAD_SURFACE, EGL_FALSE); #if EGL_TRACE if (gEGLDebugLevel > 0) 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); Loading Loading @@ -1078,7 +1102,7 @@ EGLBoolean eglReleaseThread(void) egl_tls_t::clearTLS(); #if EGL_TRACE if (gEGLDebugLevel > 0) if (getEGLDebugLevel() > 0) GLTrace_eglReleaseThread(); #endif return EGL_TRUE; Loading
opengl/libs/GLES_trace/DESIGN.txt +31 −3 Original line number Diff line number Diff line Loading @@ -9,9 +9,6 @@ Code Runtime Behavior: control whether tracing should be enabled for a certain process. If tracing is enabled, this calls GLTrace_start() to start the trace server. Note that initEglTraceLevel() is also called from early_egl_init(), but that happens in the context of the zygote, so that invocation has no effect. egl_display_t::initialize() then calls setGLHooksThreadSpecific() where we set the thread specific gl_hooks structure to point to the trace implementation. From this point on, every GLES call is redirected to the trace implementation. Loading @@ -30,6 +27,37 @@ Code Runtime Behavior: to explore if a more graceful method of stopping the application, or detaching tracing from the application is required. Enabling tracing while the application is running: In order to allow tracing of an already running application, we allow DdmServer to enable OpenGL tracing. In such a case, the application already has its GL hooks set up to point to the real GL implementation, and we need to switch them to point to the trace implementation. This is achieved by checking whether tracing should be enabled at every eglSwap call. (Note: We were already checking for tracing at every eglSwap, the only change now is that the tracing could actually be ON/OFF at runtime - earlier it was set once and never changed). If eglSwap detects that tracing should be enabled now, then it performs the following steps: - switch the gl hooks to point to the trace implementation. - call trace eglMakeCurrent to indicate that there is now a new context that is current. - continue on with tracing the eglSwap call. This switches the hooks to point to the trace implementation only for the current context. But the other contexts have their gl hooks updated when they perform eglMakeCurrent. The GLTrace version of eglMakeCurrent now has to be updated to allow switching to a context it may not know of. In such a case, it creates a context matching the version that it is now switching to. Disabling tracing: We disable tracing under two conditions: - stop tracing request from DdmServer - gltrace transport gets disconnected from the host. In either case, both actions simply disable the tracing flag. The current context gets its gl hooks restored in the next eglSwap, and the other traced contexts get their gl hooks restored when they perform a eglMakeCurrent. Code Structure: glestrace.h declares all the hooks exposed by libglestrace. These are used by EGL/egl.cpp and Loading
opengl/libs/GLES_trace/src/gltrace_eglapi.cpp +57 −10 Original line number Diff line number Diff line Loading @@ -33,6 +33,9 @@ using gltrace::GLTraceState; using gltrace::GLTraceContext; using gltrace::TCPStream; static pthread_mutex_t sGlTraceStateLock = PTHREAD_MUTEX_INITIALIZER; static int sGlTraceInProgress; static GLTraceState *sGLTraceState; static pthread_t sReceiveThreadId; Loading Loading @@ -105,33 +108,66 @@ static void *commandReceiveTask(void *arg) { return NULL; } void GLTrace_start() { char udsName[PROPERTY_VALUE_MAX]; /** * Starts Trace Server and waits for connection from the host. * Returns -1 in case of connection error, 0 otherwise. */ int GLTrace_start() { int status = 0; int clientSocket = -1; TCPStream *stream = NULL; pthread_mutex_lock(&sGlTraceStateLock); if (sGlTraceInProgress) { goto done; } char udsName[PROPERTY_VALUE_MAX]; property_get("debug.egl.debug_portname", udsName, "gltrace"); int clientSocket = gltrace::acceptClientConnection(udsName); clientSocket = gltrace::acceptClientConnection(udsName); if (clientSocket < 0) { ALOGE("Error creating GLTrace server socket. Quitting application."); exit(-1); ALOGE("Error creating GLTrace server socket. Tracing disabled."); status = -1; goto done; } sGlTraceInProgress = 1; // create communication channel to the host TCPStream *stream = new TCPStream(clientSocket); stream = new TCPStream(clientSocket); // initialize tracing state sGLTraceState = new GLTraceState(stream); pthread_create(&sReceiveThreadId, NULL, commandReceiveTask, sGLTraceState); done: pthread_mutex_unlock(&sGlTraceStateLock); return status; } void GLTrace_stop() { pthread_mutex_lock(&sGlTraceStateLock); if (sGlTraceInProgress) { sGlTraceInProgress = 0; delete sGLTraceState; sGLTraceState = NULL; } pthread_mutex_unlock(&sGlTraceStateLock); } void GLTrace_eglCreateContext(int version, EGLContext c) { pthread_mutex_lock(&sGlTraceStateLock); GLTraceState *state = sGLTraceState; pthread_mutex_unlock(&sGlTraceStateLock); if (state == NULL) return; // update trace state for new EGL context GLTraceContext *traceContext = sGLTraceState->createTraceContext(version, c); GLTraceContext *traceContext = state->createTraceContext(version, c); gltrace::setupTraceContextThreadSpecific(traceContext); // trace command through to the host Loading @@ -139,8 +175,19 @@ void GLTrace_eglCreateContext(int version, EGLContext c) { } void GLTrace_eglMakeCurrent(const unsigned version, gl_hooks_t *hooks, EGLContext c) { pthread_mutex_lock(&sGlTraceStateLock); GLTraceState *state = sGLTraceState; pthread_mutex_unlock(&sGlTraceStateLock); if (state == NULL) return; // setup per context state GLTraceContext *traceContext = sGLTraceState->getTraceContext(c); GLTraceContext *traceContext = state->getTraceContext(c); if (traceContext == NULL) { GLTrace_eglCreateContext(version, c); traceContext = state->getTraceContext(c); } traceContext->hooks = hooks; gltrace::setupTraceContextThreadSpecific(traceContext); Loading
opengl/libs/glestrace.h +1 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ void GLTrace_eglReleaseThread(); void GLTrace_eglSwapBuffers(void*, void*); /* Start and stop GL Tracing. */ void GLTrace_start(); int GLTrace_start(); void GLTrace_stop(); /* Obtain the gl_hooks structure filled with the trace implementation for all GL functions. */ Loading