[Mesa-dev] [RFC PATCH RESEND] CHROMIUM: egl/android: Dequeue buffers inside EGL calls

Tomasz Figa tfiga at chromium.org
Thu Mar 30 11:03:57 UTC 2017


Android buffer queues can be abandoned, which results in failing to
dequeue next buffer. Currently this would fail somewhere deep within
the DRI stack calling loader's getBuffers*(), without any error
reporting to the client app. However Android framework code relies on
proper signaling of this event, so we move buffer dequeue to
createWindowSurface() and swapBuffers() call, which can generate proper
EGL errors. To keep the performance benefits of delayed buffer handling,
if any, fence wait and DRI image creation is kept delayed until
getBuffers*() is called by the DRI driver.

Fixes following CTS run with i965 driver:
 cts run --module CtsCameraTest -t android.hardware.camera2.cts.RobustnessTest#testAbandonRepeatingRequestSurface

Signed-off-by: Tomasz Figa <tfiga at chromium.org>
---
 src/egl/drivers/dri2/egl_dri2.h         |   1 +
 src/egl/drivers/dri2/platform_android.c | 167 ++++++++++++++++++--------------
 2 files changed, 94 insertions(+), 74 deletions(-)

diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 2773079c99..dd9e500eb6 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -288,6 +288,7 @@ struct dri2_egl_surface
 #ifdef HAVE_ANDROID_PLATFORM
    struct ANativeWindow *window;
    struct ANativeWindowBuffer *buffer;
+   int acquire_fence_fd;
    __DRIimage *dri_image_back;
    __DRIimage *dri_image_front;
 
diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c
index 6db4015cc9..7651aa5a7b 100644
--- a/src/egl/drivers/dri2/platform_android.c
+++ b/src/egl/drivers/dri2/platform_android.c
@@ -169,15 +169,44 @@ get_native_buffer_name(struct ANativeWindowBuffer *buf)
    return gralloc_drm_get_gem_handle(buf->handle);
 }
 
-static EGLBoolean
-droid_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf)
+static __DRIbuffer *
+droid_alloc_local_buffer(struct dri2_egl_surface *dri2_surf,
+                         unsigned int att, unsigned int format)
 {
-   int fence_fd;
+   struct dri2_egl_display *dri2_dpy =
+      dri2_egl_display(dri2_surf->base.Resource.Display);
 
-   if (dri2_surf->window->dequeueBuffer(dri2_surf->window, &dri2_surf->buffer,
-                                        &fence_fd))
-      return EGL_FALSE;
+   if (att >= ARRAY_SIZE(dri2_surf->local_buffers))
+      return NULL;
+
+   if (!dri2_surf->local_buffers[att]) {
+      dri2_surf->local_buffers[att] =
+         dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format,
+               dri2_surf->base.Width, dri2_surf->base.Height);
+   }
+
+   return dri2_surf->local_buffers[att];
+}
+
+static void
+droid_free_local_buffers(struct dri2_egl_surface *dri2_surf)
+{
+   struct dri2_egl_display *dri2_dpy =
+      dri2_egl_display(dri2_surf->base.Resource.Display);
+   int i;
 
+   for (i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) {
+      if (dri2_surf->local_buffers[i]) {
+         dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
+               dri2_surf->local_buffers[i]);
+         dri2_surf->local_buffers[i] = NULL;
+      }
+   }
+}
+
+static void
+wait_and_close_acquire_fence(struct dri2_egl_surface *dri2_surf)
+{
    /* If access to the buffer is controlled by a sync fence, then block on the
     * fence.
     *
@@ -195,15 +224,36 @@ droid_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf)
     *    any value except -1) then the caller is responsible for closing the
     *    file descriptor.
     */
-    if (fence_fd >= 0) {
+    if (dri2_surf->acquire_fence_fd >= 0) {
        /* From the SYNC_IOC_WAIT documentation in <linux/sync.h>:
         *
         *    Waits indefinitely if timeout < 0.
         */
         int timeout = -1;
-        sync_wait(fence_fd, timeout);
-        close(fence_fd);
+        sync_wait(dri2_surf->acquire_fence_fd, timeout);
+        close(dri2_surf->acquire_fence_fd);
+        dri2_surf->acquire_fence_fd = -1;
    }
+}
+
+static EGLBoolean
+droid_window_dequeue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf)
+{
+   int err;
+
+   /* To avoid blocking other EGL calls, release the display mutex before
+    * we enter droid_window_enqueue_buffer() and re-acquire the mutex upon
+    * return.
+    */
+   mtx_unlock(&disp->Mutex);
+
+   err = dri2_surf->window->dequeueBuffer(dri2_surf->window, &dri2_surf->buffer,
+                                          &dri2_surf->acquire_fence_fd);
+
+   mtx_lock(&disp->Mutex);
+
+   if (err)
+      return EGL_FALSE;
 
    dri2_surf->buffer->common.incRef(&dri2_surf->buffer->common);
 
@@ -234,6 +284,14 @@ droid_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf)
       dri2_surf->back = &dri2_surf->color_buffers[0];
    }
 
+   /* free outdated buffers and update the surface size */
+   if (dri2_surf->base.Width != dri2_surf->buffer->width ||
+       dri2_surf->base.Height != dri2_surf->buffer->height) {
+      droid_free_local_buffers(dri2_surf);
+      dri2_surf->base.Width = dri2_surf->buffer->width;
+      dri2_surf->base.Height = dri2_surf->buffer->height;
+   }
+
    return EGL_TRUE;
 }
 
@@ -242,6 +300,9 @@ droid_window_enqueue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_sur
 {
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
 
+   /* In case we haven't done any rendering. */
+   wait_and_close_acquire_fence(dri2_surf);
+
    /* To avoid blocking other EGL calls, release the display mutex before
     * we enter droid_window_enqueue_buffer() and re-acquire the mutex upon
     * return.
@@ -285,41 +346,6 @@ droid_window_cancel_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf
    droid_window_enqueue_buffer(disp, dri2_surf);
 }
 
-static __DRIbuffer *
-droid_alloc_local_buffer(struct dri2_egl_surface *dri2_surf,
-                         unsigned int att, unsigned int format)
-{
-   struct dri2_egl_display *dri2_dpy =
-      dri2_egl_display(dri2_surf->base.Resource.Display);
-
-   if (att >= ARRAY_SIZE(dri2_surf->local_buffers))
-      return NULL;
-
-   if (!dri2_surf->local_buffers[att]) {
-      dri2_surf->local_buffers[att] =
-         dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format,
-               dri2_surf->base.Width, dri2_surf->base.Height);
-   }
-
-   return dri2_surf->local_buffers[att];
-}
-
-static void
-droid_free_local_buffers(struct dri2_egl_surface *dri2_surf)
-{
-   struct dri2_egl_display *dri2_dpy =
-      dri2_egl_display(dri2_surf->base.Resource.Display);
-   int i;
-
-   for (i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) {
-      if (dri2_surf->local_buffers[i]) {
-         dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
-               dri2_surf->local_buffers[i]);
-         dri2_surf->local_buffers[i] = NULL;
-      }
-   }
-}
-
 static _EGLSurface *
 droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
 		    _EGLConfig *conf, void *native_window,
@@ -336,6 +362,7 @@ droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
       _eglError(EGL_BAD_ALLOC, "droid_create_surface");
       return NULL;
    }
+   dri2_surf->acquire_fence_fd = -1;
 
    if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
       goto cleanup_surface;
@@ -377,10 +404,18 @@ droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
    if (window) {
       window->common.incRef(&window->common);
       dri2_surf->window = window;
+      if (!droid_window_dequeue_buffer(disp, dri2_surf)) {
+         _eglError(EGL_BAD_SURFACE, "Could not dequeue buffer from native window");
+         goto cleanup_window;
+      }
    }
 
    return &dri2_surf->base;
 
+cleanup_window:
+   window->common.decRef(&window->common);
+   (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
+
 cleanup_surface:
    free(dri2_surf);
 
@@ -439,29 +474,6 @@ droid_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
 }
 
 static int
-update_buffers(struct dri2_egl_surface *dri2_surf)
-{
-   if (dri2_surf->base.Type != EGL_WINDOW_BIT)
-      return 0;
-
-   /* try to dequeue the next back buffer */
-   if (!dri2_surf->buffer && !droid_window_dequeue_buffer(dri2_surf)) {
-      _eglLog(_EGL_WARNING, "Could not dequeue buffer from native window");
-      return -1;
-   }
-
-   /* free outdated buffers and update the surface size */
-   if (dri2_surf->base.Width != dri2_surf->buffer->width ||
-       dri2_surf->base.Height != dri2_surf->buffer->height) {
-      droid_free_local_buffers(dri2_surf);
-      dri2_surf->base.Width = dri2_surf->buffer->width;
-      dri2_surf->base.Height = dri2_surf->buffer->height;
-   }
-
-   return 0;
-}
-
-static int
 get_front_bo(struct dri2_egl_surface *dri2_surf, unsigned int format)
 {
    struct dri2_egl_display *dri2_dpy =
@@ -511,6 +523,10 @@ get_back_bo(struct dri2_egl_surface *dri2_surf, unsigned int format)
          return -1;
       }
 
+      /* Android might have given us an acquire fence to wait for. If so,
+       * we need to wait for it and close the descriptor after that. */
+      wait_and_close_acquire_fence(dri2_surf);
+
       fd = get_native_buffer_fd(dri2_surf->buffer);
       if (fd < 0) {
          _eglLog(_EGL_WARNING, "Could not get native buffer FD");
@@ -581,9 +597,6 @@ droid_image_get_buffers(__DRIdrawable *driDrawable,
    images->front = NULL;
    images->back = NULL;
 
-   if (update_buffers(dri2_surf) < 0)
-      return 0;
-
    if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
       if (get_front_bo(dri2_surf, format) < 0)
          return 0;
@@ -613,7 +626,7 @@ droid_query_buffer_age(_EGLDriver *drv,
 {
    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
 
-   if (update_buffers(dri2_surf) < 0) {
+   if (!dri2_surf->buffer) {
       _eglError(EGL_BAD_ALLOC, "droid_query_buffer_age");
       return 0;
    }
@@ -651,6 +664,12 @@ droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
 
    dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
 
+   /* try to dequeue the next back buffer */
+   if (!droid_window_dequeue_buffer(disp, dri2_surf)) {
+      _eglError(EGL_BAD_SURFACE, "Could not dequeue buffer from native window");
+      return EGL_FALSE;
+   }
+
    return EGL_TRUE;
 }
 
@@ -922,6 +941,9 @@ droid_get_buffers_parse_attachments(struct dri2_egl_surface *dri2_surf,
       switch (attachments[i]) {
       case __DRI_BUFFER_BACK_LEFT:
          if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
+            if (!dri2_surf->buffer)
+               continue;
+
             buf->attachment = attachments[i];
             buf->name = get_native_buffer_name(dri2_surf->buffer);
             buf->cpp = get_format_bpp(dri2_surf->buffer->format);
@@ -969,9 +991,6 @@ droid_get_buffers_with_format(__DRIdrawable * driDrawable,
 {
    struct dri2_egl_surface *dri2_surf = loaderPrivate;
 
-   if (update_buffers(dri2_surf) < 0)
-      return NULL;
-
    dri2_surf->buffer_count =
       droid_get_buffers_parse_attachments(dri2_surf, attachments, count);
 
-- 
2.12.2.564.g063fe858b8-goog



More information about the mesa-dev mailing list