From 866399093f9f60e7305f291e688abb456bace710 Mon Sep 17 00:00:00 2001 From: Riley Andrews Date: Fri, 15 Aug 2014 12:27:24 -0700 Subject: [PATCH] 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 --- services/surfaceflinger/SurfaceFlinger.cpp | 58 ++++++++++++++-------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index bbe2aa1a2..b9c70e055 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3111,6 +3111,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( */ 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 @@ status_t SurfaceFlinger::captureScreenImplLocked( 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 @@ status_t SurfaceFlinger::captureScreenImplLocked( } else { result = BAD_VALUE; } - window->queueBuffer(window, buffer, -1); + window->queueBuffer(window, buffer, syncFd); + if (syncFd != -1) { + close(syncFd); + } } } else { result = BAD_VALUE;