summaryrefslogtreecommitdiffstats
path: root/opengl
diff options
context:
space:
mode:
authorJamie Gennis <jgennis@google.com>2012-04-05 20:34:54 -0700
committerJamie Gennis <jgennis@google.com>2012-04-06 09:23:13 -0700
commit28ef8d7911dbfd1bf8256fb43acba894d87fc07a (patch)
tree121cc2605b5c244eb42f6a9c176fab1876715257 /opengl
parent8cce8a9a75d172e0077960223ac5f2d06df33892 (diff)
downloadframeworks_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.cpp77
-rw-r--r--opengl/libs/EGL/egl_display.cpp7
-rw-r--r--opengl/libs/EGL/egl_display.h3
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;