+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,
+ const EGLAttrib *attrib_list64)
+{
+ _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,
+ attrib_list64)) {
+ free(dri2_sync);
+ return NULL;
+ }
+
+ switch (type) {
+ case EGL_SYNC_FENCE_KHR:
+ dri2_sync->fence = dri2_dpy->fence->create_fence(dri2_ctx->dri_context);
+ if (!dri2_sync->fence) {
+ /* Why did it fail? DRI doesn't return an error code, so we emit
+ * a generic EGL error that doesn't communicate user error.
+ */
+ _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
+ free(dri2_sync);
+ return NULL;
+ }
+ break;
+
+ case EGL_SYNC_CL_EVENT_KHR:
+ dri2_sync->fence = dri2_dpy->fence->get_fence_from_cl_event(
+ dri2_dpy->dri_screen,
+ dri2_sync->base.CLEvent);
+ /* this can only happen if the cl_event passed in is invalid. */
+ if (!dri2_sync->fence) {
+ _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
+ free(dri2_sync);
+ return NULL;
+ }
+
+ /* the initial status must be "signaled" if the cl_event is signaled */
+ if (dri2_dpy->fence->client_wait_sync(dri2_ctx->dri_context,
+ dri2_sync->fence, 0, 0))
+ dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR;
+ 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, EGLTime 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;
+
+ /* The EGL_KHR_fence_sync spec states:
+ *
+ * "If no context is current for the bound API,
+ * the EGL_SYNC_FLUSH_COMMANDS_BIT_KHR bit is ignored.
+ */
+ if (dri2_ctx && 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 ? dri2_ctx->dri_context : NULL,
+ 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 EGLint
+dri2_server_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
+{
+ _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);
+
+ dri2_dpy->fence->server_wait_sync(dri2_ctx->dri_context,
+ dri2_sync->fence, 0);
+ return EGL_TRUE;
+}
+