egl/wgl: Support sync objects
authorJesse Natalie <jenatali@microsoft.com>
Tue, 21 Sep 2021 17:43:07 +0000 (10:43 -0700)
committerMarge Bot <emma+marge@anholt.net>
Wed, 10 Aug 2022 21:00:43 +0000 (21:00 +0000)
Acked-by: Daniel Stone <daniels@collabora.com>
Acked-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Acked-by: Sidney Just <justsid@x-plane.com>
Acked-by: Jason Ekstrand <jason.ekstrand@collabora.com>
Tested-by: Yonggang Luo <luoyonggang@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12964>

src/egl/drivers/wgl/egl_wgl.c
src/egl/drivers/wgl/egl_wgl.h

index 5a0f7a8..9922965 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <pipe/p_screen.h>
 #include <pipe/p_state.h>
+#include <pipe/p_context.h>
 
 #include <mapi/glapi/glapi.h>
 
@@ -295,6 +296,10 @@ wgl_initialize_impl(_EGLDisplay *disp, HDC hdc)
    disp->Extensions.KHR_gl_texture_cubemap_image = EGL_TRUE;
    disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE;
 
+   disp->Extensions.KHR_fence_sync = EGL_TRUE;
+   disp->Extensions.KHR_reusable_sync = EGL_TRUE;
+   disp->Extensions.KHR_wait_sync = EGL_TRUE;
+
    if (!wgl_add_configs(disp)) {
       err = "wgl: failed to add configs";
       goto cleanup;
@@ -1036,6 +1041,163 @@ wgl_destroy_image_khr(_EGLDisplay *disp, _EGLImage *img)
    return EGL_TRUE;
 }
 
+static _EGLSync *
+wgl_create_sync_khr(_EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list)
+{
+
+   _EGLContext *ctx = _eglGetCurrentContext();
+   struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx);
+   struct wgl_egl_sync *wgl_sync;
+
+   struct st_context_iface *st_ctx = wgl_ctx ? wgl_ctx->ctx->st : NULL;
+
+   wgl_sync = calloc(1, sizeof(struct wgl_egl_sync));
+   if (!wgl_sync) {
+      _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
+      return NULL;
+   }
+
+   if (!_eglInitSync(&wgl_sync->base, disp, type, attrib_list)) {
+      free(wgl_sync);
+      return NULL;
+   }
+
+   switch (type) {
+   case EGL_SYNC_FENCE_KHR:
+      st_ctx->flush(st_ctx, 0, &wgl_sync->fence, NULL, NULL);
+      if (!wgl_sync->fence) {
+         _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
+         free(wgl_sync);
+         return NULL;
+      }
+      break;
+
+   case EGL_SYNC_REUSABLE_KHR:
+      wgl_sync->event = CreateEvent(NULL, TRUE, FALSE, NULL);
+      if (!wgl_sync->event) {
+         _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
+         free(wgl_sync);
+         return NULL;
+      }
+   }
+
+   wgl_sync->refcount = 1;
+   return &wgl_sync->base;
+}
+
+static void
+wgl_egl_unref_sync(struct wgl_egl_display *wgl_dpy, struct wgl_egl_sync *wgl_sync)
+{
+   if (InterlockedDecrement((volatile LONG *)&wgl_sync->refcount) > 0)
+      return;
+
+   if (wgl_sync->fence)
+      wgl_dpy->screen->fence_reference(wgl_dpy->screen, &wgl_sync->fence, NULL);
+   if (wgl_sync->event)
+      CloseHandle(wgl_sync->event);
+   free(wgl_sync);
+}
+
+static EGLBoolean
+wgl_destroy_sync_khr(_EGLDisplay *disp, _EGLSync *sync)
+{
+   struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
+   struct wgl_egl_sync *wgl_sync = wgl_egl_sync(sync);
+   wgl_egl_unref_sync(wgl_dpy, wgl_sync);
+   return EGL_TRUE;
+}
+
+static EGLint
+wgl_client_wait_sync_khr(_EGLDisplay *disp, _EGLSync *sync, EGLint flags, EGLTime timeout)
+{
+   _EGLContext *ctx = _eglGetCurrentContext();
+   struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
+   struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx);
+   struct wgl_egl_sync *wgl_sync = wgl_egl_sync(sync);
+
+   EGLint ret = EGL_CONDITION_SATISFIED_KHR;
+
+   /* the sync object should take a reference while waiting */
+   InterlockedIncrement((volatile LONG *)&wgl_sync->refcount);
+
+   switch (sync->Type) {
+   case EGL_SYNC_FENCE_KHR:
+      if (wgl_dpy->screen->fence_finish(wgl_dpy->screen, NULL, wgl_sync->fence, timeout))
+         wgl_sync->base.SyncStatus = EGL_SIGNALED_KHR;
+      else
+         ret = EGL_TIMEOUT_EXPIRED_KHR;
+      break;
+
+   case EGL_SYNC_REUSABLE_KHR:
+      if (wgl_ctx && wgl_sync->base.SyncStatus == EGL_UNSIGNALED_KHR &&
+          (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)) {
+         /* flush context if EGL_SYNC_FLUSH_COMMANDS_BIT_KHR is set */
+         wgl_gl_flush();
+      }
+
+      DWORD wait_milliseconds = (timeout == EGL_FOREVER_KHR) ? INFINITE : (DWORD)(timeout / 1000000ull);
+      DWORD wait_ret = WaitForSingleObject(wgl_sync->event, wait_milliseconds);
+      switch (wait_ret) {
+      case WAIT_OBJECT_0:
+         assert(wgl_sync->base.SyncStatus == EGL_SIGNALED_KHR);
+         break;
+      case WAIT_TIMEOUT:
+         assert(wgl_sync->base.SyncStatus == EGL_UNSIGNALED_KHR);
+         ret = EGL_TIMEOUT_EXPIRED_KHR;
+         break;
+      default:
+         _eglError(EGL_BAD_ACCESS, "eglClientWaitSyncKHR");
+         ret = EGL_FALSE;
+         break;
+      }
+      break;
+  }
+  wgl_egl_unref_sync(wgl_dpy, wgl_sync);
+
+  return ret;
+}
+
+static EGLint
+wgl_wait_sync_khr(_EGLDisplay *disp, _EGLSync *sync)
+{
+   _EGLContext *ctx = _eglGetCurrentContext();
+   struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx);
+   struct wgl_egl_sync *wgl_sync = wgl_egl_sync(sync);
+
+   if (!wgl_sync->fence)
+      return EGL_TRUE;
+
+   struct pipe_context *pipe = wgl_ctx->ctx->st->pipe;
+   if (pipe->fence_server_sync)
+      pipe->fence_server_sync(pipe, wgl_sync->fence);
+
+   return EGL_TRUE;
+}
+
+static EGLBoolean
+wgl_signal_sync_khr(_EGLDisplay *disp, _EGLSync *sync, EGLenum mode)
+{
+   struct wgl_egl_sync *wgl_sync = wgl_egl_sync(sync);
+
+   if (sync->Type != EGL_SYNC_REUSABLE_KHR)
+      return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR");
+
+   if (mode != EGL_SIGNALED_KHR && mode != EGL_UNSIGNALED_KHR)
+      return _eglError(EGL_BAD_ATTRIBUTE, "eglSignalSyncKHR");
+
+   wgl_sync->base.SyncStatus = mode;
+
+   if (mode == EGL_SIGNALED_KHR) {
+      if (!SetEvent(wgl_sync->event))
+         return _eglError(EGL_BAD_ACCESS, "eglSignalSyncKHR");
+   } else {
+      if (!ResetEvent(wgl_sync->event))
+         return _eglError(EGL_BAD_ACCESS, "eglSignalSyncKHR");
+   }
+
+   return EGL_TRUE;
+}
+
 static const char *
 wgl_query_driver_name(_EGLDisplay *disp)
 {
@@ -1067,6 +1229,11 @@ struct _egl_driver _eglDriver = {
    .WaitNative = wgl_wait_native,
    .CreateImageKHR = wgl_create_image_khr,
    .DestroyImageKHR = wgl_destroy_image_khr,
+   .CreateSyncKHR = wgl_create_sync_khr,
+   .DestroySyncKHR = wgl_destroy_sync_khr,
+   .ClientWaitSyncKHR = wgl_client_wait_sync_khr,
+   .WaitSyncKHR = wgl_wait_sync_khr,
+   .SignalSyncKHR = wgl_signal_sync_khr,
    .QueryDriverName = wgl_query_driver_name,
    .QueryDriverConfig = wgl_query_driver_config,
 };
index b609fd9..b9b99f0 100644 (file)
@@ -27,6 +27,7 @@
 #include <egldisplay.h>
 #include <eglconfig.h>
 #include <eglimage.h>
+#include <eglsync.h>
 
 #include <stw_pixelformat.h>
 #include <windows.h>
@@ -63,5 +64,14 @@ struct wgl_egl_image
    struct stw_image *img;
 };
 
+struct wgl_egl_sync
+{
+   _EGLSync base;
+   int refcount;
+   struct pipe_fence_handle *fence;
+   HANDLE event;
+};
+
 _EGL_DRIVER_STANDARD_TYPECASTS(wgl_egl)
 _EGL_DRIVER_TYPECAST(wgl_egl_image, _EGLImage, obj)
+_EGL_DRIVER_TYPECAST(wgl_egl_sync, _EGLSync, obj)