egl/dri2: implement EGL_KHR_fence_sync
authorMarek Olšák <marek.olsak@amd.com>
Fri, 10 Apr 2015 08:56:02 +0000 (10:56 +0200)
committerMarek Olšák <marek.olsak@amd.com>
Thu, 30 Apr 2015 12:38:38 +0000 (14:38 +0200)
src/egl/drivers/dri2/egl_dri2.c
src/egl/drivers/dri2/egl_dri2.h
src/egl/main/eglapi.c

index 14b9be90bd07f607adec94e102649c04f85e367e..97175aef4d58c37b0863cf5aaeb724947601504a 100644 (file)
@@ -51,6 +51,7 @@
 #endif
 
 #include "egl_dri2.h"
+#include "../util/u_atomic.h"
 
 const __DRIuseInvalidateExtension use_invalidate = {
    .base = { __DRI_USE_INVALIDATE, 1 }
@@ -527,6 +528,10 @@ dri2_setup_screen(_EGLDisplay *disp)
          disp->Extensions.EXT_create_context_robustness = EGL_TRUE;
    }
 
+   if (dri2_dpy->fence) {
+      disp->Extensions.KHR_fence_sync = EGL_TRUE;
+   }
+
    if (dri2_dpy->image) {
       if (dri2_dpy->image->base.version >= 10 &&
           dri2_dpy->image->getCapabilities != NULL) {
@@ -620,6 +625,9 @@ dri2_create_screen(_EGLDisplay *disp)
         if (strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0) {
            dri2_dpy->config = (__DRI2configQueryExtension *) extensions[i];
         }
+         if (strcmp(extensions[i]->name, __DRI2_FENCE) == 0) {
+            dri2_dpy->fence = (__DRI2fenceExtension *) extensions[i];
+         }
       }
    } else {
       assert(dri2_dpy->swrast);
@@ -2180,6 +2188,90 @@ dri2_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp,
 }
 #endif
 
+static void
+dri2_egl_ref_sync(struct dri2_egl_sync *sync)
+{
+   p_atomic_inc(&sync->refcount);
+}
+
+static void
+dri2_egl_unref_sync(struct dri2_egl_display *dri2_dpy,
+                    struct dri2_egl_sync *dri2_sync)
+{
+   if (p_atomic_dec_zero(&dri2_sync->refcount)) {
+      dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence);
+      free(dri2_sync);
+   }
+}
+
+static _EGLSync *
+dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy,
+                 EGLenum type, const EGLint *attrib_list)
+{
+   _EGLContext *ctx = _eglGetCurrentContext();
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
+   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+   struct dri2_egl_sync *dri2_sync;
+
+   dri2_sync = calloc(1, sizeof(struct dri2_egl_sync));
+   if (!dri2_sync) {
+      _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
+      return NULL;
+   }
+
+   if (!_eglInitSync(&dri2_sync->base, dpy, type, attrib_list)) {
+      free(dri2_sync);
+      return NULL;
+   }
+
+   switch (type) {
+   case EGL_SYNC_FENCE_KHR:
+      dri2_sync->fence = dri2_dpy->fence->create_fence(dri2_ctx->dri_context);
+      break;
+   }
+
+   p_atomic_set(&dri2_sync->refcount, 1);
+   return &dri2_sync->base;
+}
+
+static EGLBoolean
+dri2_destroy_sync(_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);
+
+   dri2_egl_unref_sync(dri2_dpy, dri2_sync);
+   return EGL_TRUE;
+}
+
+static EGLint
+dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
+                      EGLint flags, EGLTimeKHR timeout)
+{
+   _EGLContext *ctx = _eglGetCurrentContext();
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
+   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+   struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
+   unsigned wait_flags = 0;
+   EGLint ret = EGL_CONDITION_SATISFIED_KHR;
+
+   if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)
+      wait_flags |= __DRI2_FENCE_FLAG_FLUSH_COMMANDS;
+
+   /* the sync object should take a reference while waiting */
+   dri2_egl_ref_sync(dri2_sync);
+
+   if (dri2_dpy->fence->client_wait_sync(dri2_ctx->dri_context,
+                                         dri2_sync->fence, wait_flags,
+                                         timeout))
+      dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR;
+   else
+      ret = EGL_TIMEOUT_EXPIRED_KHR;
+
+   dri2_egl_unref_sync(dri2_dpy, dri2_sync);
+   return ret;
+}
+
 static void
 dri2_unload(_EGLDriver *drv)
 {
@@ -2292,6 +2384,9 @@ _eglBuiltInDriverDRI2(const char *args)
    dri2_drv->base.API.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl;
 #endif
    dri2_drv->base.API.GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium;
+   dri2_drv->base.API.CreateSyncKHR = dri2_create_sync;
+   dri2_drv->base.API.ClientWaitSyncKHR = dri2_client_wait_sync;
+   dri2_drv->base.API.DestroySyncKHR = dri2_destroy_sync;
 
    dri2_drv->base.Name = "DRI2";
    dri2_drv->base.Unload = dri2_unload;
index 167b3b18c6f1ee55a94bd9aab88ccaf9b45ea66b..371fb4aee4ac41cc0d3a86a8982813ee4319d7e9 100644 (file)
@@ -74,6 +74,7 @@
 #include "egllog.h"
 #include "eglsurface.h"
 #include "eglimage.h"
+#include "eglsync.h"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
@@ -164,6 +165,7 @@ struct dri2_egl_display
    const __DRIimageExtension      *image;
    const __DRIrobustnessExtension *robustness;
    const __DRI2configQueryExtension *config;
+   const __DRI2fenceExtension *fence;
    int                       fd;
 
    int                       own_device;
@@ -283,6 +285,12 @@ struct dri2_egl_image
    __DRIimage *dri_image;
 };
 
+struct dri2_egl_sync {
+   _EGLSync base;
+   int refcount;
+   void *fence;
+};
+
 /* From xmlpool/options.h, user exposed so should be stable */
 #define DRI_CONF_VBLANK_NEVER 0
 #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
@@ -292,6 +300,7 @@ struct dri2_egl_image
 /* standard typecasts */
 _EGL_DRIVER_STANDARD_TYPECASTS(dri2_egl)
 _EGL_DRIVER_TYPECAST(dri2_egl_image, _EGLImage, obj)
+_EGL_DRIVER_TYPECAST(dri2_egl_sync, _EGLSync, obj)
 
 extern const __DRIimageLookupExtension image_lookup_extension;
 extern const __DRIuseInvalidateExtension use_invalidate;
index 8b7b9bee7f1efb4a74c1928a79c8fa997525fdce..dd972b2edb8cc0f38a755ca4372674bf2634ecf6 100644 (file)
@@ -1657,13 +1657,30 @@ EGLSyncKHR EGLAPIENTRY
 eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
 {
    _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLContext *ctx = _eglGetCurrentContext();
    _EGLDriver *drv;
    _EGLSync *sync;
    EGLSyncKHR ret;
 
    _EGL_CHECK_DISPLAY(disp, EGL_NO_SYNC_KHR, drv);
-   if (!disp->Extensions.KHR_reusable_sync)
-      RETURN_EGL_EVAL(disp, EGL_NO_SYNC_KHR);
+
+   /* return an error if the client API doesn't support GL_OES_EGL_sync */
+   if (!ctx || ctx->Resource.Display != dpy ||
+       ctx->ClientAPI != EGL_OPENGL_ES_API)
+      RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
+
+   switch (type) {
+   case EGL_SYNC_FENCE_KHR:
+      if (!disp->Extensions.KHR_fence_sync)
+         RETURN_EGL_ERROR(disp, EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
+      break;
+   case EGL_SYNC_REUSABLE_KHR:
+      if (!disp->Extensions.KHR_reusable_sync)
+         RETURN_EGL_ERROR(disp, EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
+      break;
+   default:
+      RETURN_EGL_ERROR(disp, EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
+   }
 
    sync = drv->API.CreateSyncKHR(drv, disp, type, attrib_list);
    ret = (sync) ? _eglLinkSync(sync) : EGL_NO_SYNC_KHR;
@@ -1681,7 +1698,8 @@ eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
    EGLBoolean ret;
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
-   assert(disp->Extensions.KHR_reusable_sync);
+   assert(disp->Extensions.KHR_reusable_sync ||
+          disp->Extensions.KHR_fence_sync);
 
    _eglUnlinkSync(s);
    ret = drv->API.DestroySyncKHR(drv, disp, s);
@@ -1699,7 +1717,12 @@ eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR t
    EGLint ret;
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
-   assert(disp->Extensions.KHR_reusable_sync);
+   assert(disp->Extensions.KHR_reusable_sync ||
+          disp->Extensions.KHR_fence_sync);
+
+   if (s->SyncStatus == EGL_SIGNALED_KHR)
+      RETURN_EGL_EVAL(disp, EGL_CONDITION_SATISFIED_KHR);
+
    ret = drv->API.ClientWaitSyncKHR(drv, disp, s, flags, timeout);
 
    RETURN_EGL_EVAL(disp, ret);
@@ -1731,7 +1754,8 @@ eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *v
    EGLBoolean ret;
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
-   assert(disp->Extensions.KHR_reusable_sync);
+   assert(disp->Extensions.KHR_reusable_sync ||
+          disp->Extensions.KHR_fence_sync);
    ret = drv->API.GetSyncAttribKHR(drv, disp, s, attribute, value);
 
    RETURN_EGL_EVAL(disp, ret);