diff options
author | Jamie Gennis <jgennis@google.com> | 2012-04-05 20:34:54 -0700 |
---|---|---|
committer | Jamie Gennis <jgennis@google.com> | 2012-04-06 09:23:13 -0700 |
commit | 28ef8d7911dbfd1bf8256fb43acba894d87fc07a (patch) | |
tree | 121cc2605b5c244eb42f6a9c176fab1876715257 /opengl | |
parent | 8cce8a9a75d172e0077960223ac5f2d06df33892 (diff) | |
download | frameworks_native-28ef8d7911dbfd1bf8256fb43acba894d87fc07a.zip frameworks_native-28ef8d7911dbfd1bf8256fb43acba894d87fc07a.tar.gz frameworks_native-28ef8d7911dbfd1bf8256fb43acba894d87fc07a.tar.bz2 |
EGL: add GPU frame completion tracing
This change adds a debug option to EGL to use an EGLSyncKHR each frame to
determine when the GPU finishes rendering the frame.
Change-Id: I09ce071db904b44f07ca814c586c291c8b59385a
Diffstat (limited to 'opengl')
-rw-r--r-- | opengl/libs/EGL/eglApi.cpp | 77 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_display.cpp | 7 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_display.h | 3 |
3 files changed, 84 insertions, 3 deletions
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 8bfa16d..8df7d39 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -715,6 +715,69 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) return addr; } +class FrameCompletionThread : public Thread { +public: + + static void queueSync(EGLSyncKHR sync) { + static sp<FrameCompletionThread> thread(new FrameCompletionThread); + static bool running = false; + if (!running) { + thread->run("GPUFrameCompletion"); + running = true; + } + { + Mutex::Autolock lock(thread->mMutex); + ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d", + thread->mFramesQueued).string()); + thread->mQueue.push_back(sync); + thread->mCondition.signal(); + thread->mFramesQueued++; + ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size()); + } + } + +private: + FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {} + + virtual bool threadLoop() { + EGLSyncKHR sync; + uint32_t frameNum; + { + Mutex::Autolock lock(mMutex); + while (mQueue.isEmpty()) { + mCondition.wait(mMutex); + } + sync = mQueue[0]; + frameNum = mFramesCompleted; + } + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + { + ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d", + frameNum).string()); + EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR); + if (result == EGL_FALSE) { + ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError()); + } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { + ALOGE("FrameCompletion: timeout waiting for fence"); + } + eglDestroySyncKHR(dpy, sync); + } + { + Mutex::Autolock lock(mMutex); + mQueue.removeAt(0); + mFramesCompleted++; + ATRACE_INT("GPU Frames Outstanding", mQueue.size()); + } + return true; + } + + uint32_t mFramesQueued; + uint32_t mFramesCompleted; + Vector<EGLSyncKHR> mQueue; + Condition mCondition; + Mutex mMutex; +}; + EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) { ATRACE_CALL(); @@ -744,7 +807,19 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) } } - return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); + EGLBoolean result = s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); + + if (CC_UNLIKELY(dp->traceGpuCompletion)) { + EGLSyncKHR sync = EGL_NO_SYNC_KHR; + { + sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); + } + if (sync != EGL_NO_SYNC_KHR) { + FrameCompletionThread::queueSync(sync); + } + } + + return result; } EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index b80afd6..6b6f8cf 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -67,7 +67,7 @@ extern void setGLHooksThreadSpecific(gl_hooks_t const *value); egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; egl_display_t::egl_display_t() : - magic('_dpy'), finishOnSwap(false), refs(0) { + magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0) { } egl_display_t::~egl_display_t() { @@ -239,6 +239,11 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { finishOnSwap = true; } + property_get("debug.egl.traceGpuCompletion", value, "0"); + if (atoi(value)) { + traceGpuCompletion = true; + } + refs++; if (major != NULL) *major = VERSION_MAJOR; diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h index 43738ea..3e22efa 100644 --- a/opengl/libs/EGL/egl_display.h +++ b/opengl/libs/EGL/egl_display.h @@ -107,7 +107,8 @@ private: public: DisplayImpl disp; - bool finishOnSwap; + bool finishOnSwap; // property: debug.egl.finish + bool traceGpuCompletion; // property: debug.egl.traceGpuCompletion private: uint32_t refs; |