Take advantage of sync points during screen cap.

Do not wait for the screen capture to complete within surface flinger,
instead pass a sync point back with the captured gralloc buffer.

Change-Id: I7137c0e0fc710688d1d61f189159418fb27ea263
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bbe2aa1..b9c70e0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3111,6 +3111,7 @@
              */
             result = native_window_dequeue_buffer_and_wait(window,  &buffer);
             if (result == NO_ERROR) {
+                int syncFd = -1;
                 // create an EGLImage from the buffer so we can later
                 // turn it into a texture
                 EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
@@ -3127,27 +3128,41 @@
                         renderScreenImplLocked(hw, sourceCrop, reqWidth, reqHeight,
                                 minLayerZ, maxLayerZ, true, useIdentityTransform);
 
-                        // Create a sync point and wait on it, so we know the buffer is
-                        // ready before we pass it along.  We can't trivially call glFlush(),
-                        // so we use a wait flag instead.
-                        // TODO: pass a sync fd to queueBuffer() and let the consumer wait.
-                        EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
-                        if (sync != EGL_NO_SYNC_KHR) {
-                            EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
-                                    EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
-                            EGLint eglErr = eglGetError();
-                            eglDestroySyncKHR(mEGLDisplay, sync);
-                            if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-                                ALOGW("captureScreen: fence wait timed out");
-                            } else {
-                                ALOGW_IF(eglErr != EGL_SUCCESS,
-                                        "captureScreen: error waiting on EGL fence: %#x", eglErr);
-                            }
+                        // Attempt to create a sync khr object that can produce a sync point. If that
+                        // isn't available, create a non-dupable sync object in the fallback path and
+                        // wait on it directly.
+                        EGLSyncKHR sync;
+                        if (!DEBUG_SCREENSHOTS) {
+                           sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
                         } else {
-                            ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
-                            // not fatal
+                            sync = EGL_NO_SYNC_KHR;
                         }
-
+                        if (sync != EGL_NO_SYNC_KHR) {
+                            // get the sync fd
+                            syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
+                            if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+                                ALOGW("captureScreen: failed to dup sync khr object");
+                                syncFd = -1;
+                            }
+                            eglDestroySyncKHR(mEGLDisplay, sync);
+                        } else {
+                            // fallback path
+                            sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
+                            if (sync != EGL_NO_SYNC_KHR) {
+                                EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
+                                    EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
+                                EGLint eglErr = eglGetError();
+                                if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+                                    ALOGW("captureScreen: fence wait timed out");
+                                } else {
+                                    ALOGW_IF(eglErr != EGL_SUCCESS,
+                                            "captureScreen: error waiting on EGL fence: %#x", eglErr);
+                                }
+                                eglDestroySyncKHR(mEGLDisplay, sync);
+                            } else {
+                                ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
+                            }
+                        }
                         if (DEBUG_SCREENSHOTS) {
                             uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
                             getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
@@ -3165,7 +3180,10 @@
                 } else {
                     result = BAD_VALUE;
                 }
-                window->queueBuffer(window, buffer, -1);
+                window->queueBuffer(window, buffer, syncFd);
+                if (syncFd != -1) {
+                    close(syncFd);
+                }
             }
         } else {
             result = BAD_VALUE;