egl: add EGL_ANDROID_native_fence_sync
authorRob Clark <robclark@freedesktop.org>
Fri, 18 Nov 2016 13:39:33 +0000 (08:39 -0500)
committerChad Versace <chadversary@chromium.org>
Thu, 1 Dec 2016 18:57:35 +0000 (10:57 -0800)
With fixes from Chad squashed in, plus fixes for issues that Rafael
found while writing piglit tests.

Signed-off-by: Rob Clark <robclark@freedesktop.org>
Tested-by: Rafael Antognolli <rafael.antognolli@intel.com>
Reviewed-by: Chad Versace <chadversary@chromium.org>
Tested-by: Chad Versace <chadversary@chromium.org>
src/egl/drivers/dri2/egl_dri2.c
src/egl/main/eglapi.c
src/egl/main/eglapi.h
src/egl/main/egldisplay.h
src/egl/main/eglfallbacks.c
src/egl/main/eglsync.c
src/egl/main/eglsync.h

index f18e9fbd673a4dae8d7ef5845404f054fc7b3eb3..52fbdff0b128d1ad3e52e792f4f3b4e72d1b38bf 100644 (file)
@@ -658,6 +658,12 @@ dri2_setup_screen(_EGLDisplay *disp)
       disp->Extensions.KHR_wait_sync = EGL_TRUE;
       if (dri2_dpy->fence->get_fence_from_cl_event)
          disp->Extensions.KHR_cl_event2 = EGL_TRUE;
+      if (dri2_dpy->fence->base.version >= 2) {
+         unsigned capabilities =
+            dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen);
+         disp->Extensions.ANDROID_native_fence_sync =
+            (capabilities & __DRI_FENCE_CAP_NATIVE_FD) != 0;
+      }
    }
 
    disp->Extensions.KHR_reusable_sync = EGL_TRUE;
@@ -2511,8 +2517,17 @@ dri2_egl_unref_sync(struct dri2_egl_display *dri2_dpy,
                     struct dri2_egl_sync *dri2_sync)
 {
    if (p_atomic_dec_zero(&dri2_sync->refcount)) {
-      if (dri2_sync->base.Type == EGL_SYNC_REUSABLE_KHR)
+      switch (dri2_sync->base.Type) {
+      case EGL_SYNC_REUSABLE_KHR:
          cnd_destroy(&dri2_sync->cond);
+         break;
+      case EGL_SYNC_NATIVE_FENCE_ANDROID:
+         if (dri2_sync->base.SyncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID)
+            close(dri2_sync->base.SyncFd);
+         break;
+      default:
+         break;
+      }
 
       if (dri2_sync->fence)
          dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence);
@@ -2603,6 +2618,19 @@ dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy,
       /* initial status of reusable sync must be "unsignaled" */
       dri2_sync->base.SyncStatus = EGL_UNSIGNALED_KHR;
       break;
+
+   case EGL_SYNC_NATIVE_FENCE_ANDROID:
+      if (dri2_dpy->fence->create_fence_fd) {
+         dri2_sync->fence = dri2_dpy->fence->create_fence_fd(
+                                    dri2_ctx->dri_context,
+                                    dri2_sync->base.SyncFd);
+      }
+      if (!dri2_sync->fence) {
+         _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
+         free(dri2_sync);
+         return NULL;
+      }
+      break;
    }
 
    p_atomic_set(&dri2_sync->refcount, 1);
@@ -2632,11 +2660,37 @@ dri2_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
          ret = EGL_FALSE;
       }
    }
+
    dri2_egl_unref_sync(dri2_dpy, dri2_sync);
 
    return ret;
 }
 
+static EGLint
+dri2_dup_native_fence_fd(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
+   struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
+
+   assert(sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID);
+
+   if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+      /* try to retrieve the actual native fence fd.. if rendering is
+       * not flushed this will just return -1, aka NO_NATIVE_FENCE_FD:
+       */
+      sync->SyncFd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen,
+                                                   dri2_sync->fence);
+   }
+
+   if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+      /* if native fence fd still not created, return an error: */
+      _eglError(EGL_BAD_PARAMETER, "eglDupNativeFenceFDANDROID");
+      return EGL_NO_NATIVE_FENCE_FD_ANDROID;
+   }
+
+   return dup(sync->SyncFd);
+}
+
 static EGLint
 dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
                       EGLint flags, EGLTime timeout)
@@ -2667,6 +2721,7 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
 
    switch (sync->Type) {
    case EGL_SYNC_FENCE_KHR:
+   case EGL_SYNC_NATIVE_FENCE_ANDROID:
    case EGL_SYNC_CL_EVENT_KHR:
       if (dri2_dpy->fence->client_wait_sync(dri2_ctx ? dri2_ctx->dri_context : NULL,
                                          dri2_sync->fence, wait_flags,
@@ -2922,6 +2977,7 @@ _eglBuiltInDriverDRI2(const char *args)
    dri2_drv->base.API.DestroySyncKHR = dri2_destroy_sync;
    dri2_drv->base.API.GLInteropQueryDeviceInfo = dri2_interop_query_device_info;
    dri2_drv->base.API.GLInteropExportObject = dri2_interop_export_object;
+   dri2_drv->base.API.DupNativeFenceFDANDROID = dri2_dup_native_fence_fd;
 
    dri2_drv->base.Name = "DRI2";
    dri2_drv->base.Unload = dri2_unload;
index 4a4431534ffa5278c288c8c0d8539703818d6a44..9950a7210f3db8df4d34c734bc89633141818050 100644 (file)
@@ -474,6 +474,7 @@ _eglCreateExtensionsString(_EGLDisplay *dpy)
    /* Please keep these sorted alphabetically. */
    _EGL_CHECK_EXTENSION(ANDROID_framebuffer_target);
    _EGL_CHECK_EXTENSION(ANDROID_image_native_buffer);
+   _EGL_CHECK_EXTENSION(ANDROID_native_fence_sync);
    _EGL_CHECK_EXTENSION(ANDROID_recordable);
 
    _EGL_CHECK_EXTENSION(CHROMIUM_sync_control);
@@ -1609,7 +1610,8 @@ _eglCreateSync(_EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list,
     * (i.e., eglGetCurrentContext returns EGL_NO_CONTEXT ), an EGL_BAD_MATCH
     * error is generated.
     */
-   if (!ctx && type == EGL_SYNC_FENCE_KHR)
+   if (!ctx &&
+       (type == EGL_SYNC_FENCE_KHR || type == EGL_SYNC_NATIVE_FENCE_ANDROID))
       RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
 
    /* return an error if the client API doesn't support GL_OES_EGL_sync */
@@ -1630,6 +1632,10 @@ _eglCreateSync(_EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list,
       if (!disp->Extensions.KHR_cl_event2)
          RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR);
       break;
+   case EGL_SYNC_NATIVE_FENCE_ANDROID:
+      if (!disp->Extensions.ANDROID_native_fence_sync)
+         RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR);
+      break;
    default:
       RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR);
    }
@@ -1702,7 +1708,8 @@ eglDestroySync(EGLDisplay dpy, EGLSync sync)
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
    assert(disp->Extensions.KHR_reusable_sync ||
-          disp->Extensions.KHR_fence_sync);
+          disp->Extensions.KHR_fence_sync ||
+          disp->Extensions.ANDROID_native_fence_sync);
 
    _eglUnlinkSync(s);
    ret = drv->API.DestroySyncKHR(drv, disp, s);
@@ -1723,7 +1730,8 @@ eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout)
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
    assert(disp->Extensions.KHR_reusable_sync ||
-          disp->Extensions.KHR_fence_sync);
+          disp->Extensions.KHR_fence_sync ||
+          disp->Extensions.ANDROID_native_fence_sync);
 
    if (s->SyncStatus == EGL_SIGNALED_KHR)
       RETURN_EGL_EVAL(disp, EGL_CONDITION_SATISFIED_KHR);
@@ -1822,7 +1830,8 @@ _eglGetSyncAttribCommon(_EGLDisplay *disp, _EGLSync *s, EGLint attribute, EGLAtt
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
    assert(disp->Extensions.KHR_reusable_sync ||
-          disp->Extensions.KHR_fence_sync);
+          disp->Extensions.KHR_fence_sync ||
+          disp->Extensions.ANDROID_native_fence_sync);
    ret = drv->API.GetSyncAttrib(drv, disp, s, attribute, value);
 
    RETURN_EGL_EVAL(disp, ret);
@@ -1865,6 +1874,29 @@ eglGetSyncAttribKHR(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *valu
    return result;
 }
 
+static EGLint EGLAPIENTRY
+eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSync sync)
+{
+   _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLSync *s = _eglLookupSync(sync, disp);
+   _EGLDriver *drv;
+   EGLBoolean ret;
+
+   _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE);
+
+   /* the spec doesn't seem to specify what happens if the fence
+    * type is not EGL_SYNC_NATIVE_FENCE_ANDROID, but this seems
+    * sensible:
+    */
+   if (!(s && (s->Type == EGL_SYNC_NATIVE_FENCE_ANDROID)))
+      RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_NO_NATIVE_FENCE_FD_ANDROID);
+
+   _EGL_CHECK_SYNC(disp, s, EGL_NO_NATIVE_FENCE_FD_ANDROID, drv);
+   assert(disp->Extensions.ANDROID_native_fence_sync);
+   ret = drv->API.DupNativeFenceFDANDROID(drv, disp, s);
+
+   RETURN_EGL_EVAL(disp, ret);
+}
 
 static EGLBoolean EGLAPIENTRY
 eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface,
@@ -2340,6 +2372,7 @@ eglGetProcAddress(const char *procname)
       { "eglLabelObjectKHR", (_EGLProc) eglLabelObjectKHR },
       { "eglDebugMessageControlKHR", (_EGLProc) eglDebugMessageControlKHR },
       { "eglQueryDebugKHR", (_EGLProc) eglQueryDebugKHR },
+      { "eglDupNativeFenceFDANDROID", (_EGLProc) eglDupNativeFenceFDANDROID },
       { NULL, NULL }
    };
    EGLint i;
index b9bcc8ec8c79d6cc7adc520806f46f93266b10cd..2dc89fc655a03c1975807ab934ea5edae9e25a15 100644 (file)
@@ -146,6 +146,8 @@ struct _egl_api
    EGLBoolean (*GetSyncAttrib)(_EGLDriver *drv, _EGLDisplay *dpy,
                                _EGLSync *sync, EGLint attribute,
                                EGLAttrib *value);
+   EGLint (*DupNativeFenceFDANDROID)(_EGLDriver *drv, _EGLDisplay *dpy,
+                                     _EGLSync *sync);
 
    EGLBoolean (*SwapBuffersRegionNOK)(_EGLDriver *drv, _EGLDisplay *disp,
                                       _EGLSurface *surf, EGLint numRects,
index 62d9a112f1f4de2a035e519b88c59d1e2bbe296b..4e0d717c8328b83e6cd0911f87b7c55d482d231a 100644 (file)
@@ -94,6 +94,7 @@ struct _egl_extensions
    /* Please keep these sorted alphabetically. */
    EGLBoolean ANDROID_framebuffer_target;
    EGLBoolean ANDROID_image_native_buffer;
+   EGLBoolean ANDROID_native_fence_sync;
    EGLBoolean ANDROID_recordable;
 
    EGLBoolean CHROMIUM_sync_control;
index d0fce8c20defba7cd1eaf10be588d917e7591975..017d337133e6e09e33e752543b3948eda25900d3 100644 (file)
@@ -92,6 +92,7 @@ _eglInitDriverFallbacks(_EGLDriver *drv)
    drv->API.WaitSyncKHR = NULL;
    drv->API.SignalSyncKHR = NULL;
    drv->API.GetSyncAttrib = _eglGetSyncAttrib;
+   drv->API.DupNativeFenceFDANDROID = NULL;
 
    drv->API.CreateDRMImageMESA = NULL;
    drv->API.ExportDRMImageMESA = NULL;
index 7b2c882d813c10c0938f51f46aeb1fb0608d2345..cb931b816827248369f0586c3d9d72109fdcebe5 100644 (file)
@@ -59,6 +59,14 @@ _eglParseSyncAttribList(_EGLSync *sync, const EGLAttrib *attrib_list)
             err = EGL_BAD_ATTRIBUTE;
          }
          break;
+      case EGL_SYNC_NATIVE_FENCE_FD_ANDROID:
+         if (sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID) {
+            /* we take ownership of the native fd, so no dup(): */
+            sync->SyncFd = val;
+         } else {
+            err = EGL_BAD_ATTRIBUTE;
+         }
+         break;
       default:
          err = EGL_BAD_ATTRIBUTE;
          break;
@@ -83,6 +91,7 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
    _eglInitResource(&sync->Resource, sizeof(*sync), dpy);
    sync->Type = type;
    sync->SyncStatus = EGL_UNSIGNALED_KHR;
+   sync->SyncFd = EGL_NO_NATIVE_FENCE_FD_ANDROID;
 
    err = _eglParseSyncAttribList(sync, attrib_list);
 
@@ -90,6 +99,12 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
    case EGL_SYNC_CL_EVENT_KHR:
       sync->SyncCondition = EGL_SYNC_CL_EVENT_COMPLETE_KHR;
       break;
+   case EGL_SYNC_NATIVE_FENCE_ANDROID:
+      if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID)
+         sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
+      else
+         sync->SyncCondition = EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID;
+      break;
    default:
       sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
    }
@@ -117,17 +132,20 @@ _eglGetSyncAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
       if (sync->SyncStatus != EGL_SIGNALED_KHR &&
           (sync->Type == EGL_SYNC_FENCE_KHR ||
            sync->Type == EGL_SYNC_CL_EVENT_KHR ||
-          sync->Type == EGL_SYNC_REUSABLE_KHR))
+           sync->Type == EGL_SYNC_REUSABLE_KHR ||
+           sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID))
          drv->API.ClientWaitSyncKHR(drv, dpy, sync, 0, 0);
 
       *value = sync->SyncStatus;
       break;
    case EGL_SYNC_CONDITION_KHR:
       if (sync->Type != EGL_SYNC_FENCE_KHR &&
-          sync->Type != EGL_SYNC_CL_EVENT_KHR)
+          sync->Type != EGL_SYNC_CL_EVENT_KHR &&
+          sync->Type != EGL_SYNC_NATIVE_FENCE_ANDROID)
          return _eglError(EGL_BAD_ATTRIBUTE, "eglGetSyncAttribKHR");
       *value = sync->SyncCondition;
       break;
+
    default:
       return _eglError(EGL_BAD_ATTRIBUTE, "eglGetSyncAttribKHR");
       break;
index 83b6f72fce8304efecbfe8ca0ca0a889e0fb99fa..5ac76f3ac3dfd3e64fa67135e3c3308f33b9f3aa 100644 (file)
@@ -48,6 +48,7 @@ struct _egl_sync
    EGLenum SyncStatus;
    EGLenum SyncCondition;
    EGLAttrib CLEvent;
+   EGLint SyncFd;
 };