[RFC xserver 10/12] modesetting: Add implementation for in-fences

Louis-Francis Ratté-Boulianne lfrb at collabora.com
Wed Aug 30 05:16:59 UTC 2017


Allow the modesetting present implementation to wait on
in-fences using ANDROID_native_fence_sync if the fence
was created with DRI3 FenceFromDMAFenceFD.

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
---
 configure.ac                                     |  1 +
 glamor/Makefile.am                               |  2 +
 glamor/glamor.c                                  | 19 ++++++
 glamor/glamor.h                                  |  7 +++
 glamor/glamor_egl.c                              | 44 ++++++++++++++
 glamor/glamor_egl_stubs.c                        |  6 ++
 hw/xfree86/drivers/modesetting/dri2.c            |  2 +-
 hw/xfree86/drivers/modesetting/driver.h          |  1 +
 hw/xfree86/drivers/modesetting/drmmode_display.c |  7 ++-
 hw/xfree86/drivers/modesetting/drmmode_display.h |  2 +-
 hw/xfree86/drivers/modesetting/pageflip.c        | 17 ++++--
 hw/xfree86/drivers/modesetting/present.c         | 77 +++++++++++++++++++++++-
 hw/xwayland/xwayland-glamor.c                    | 12 ++++
 13 files changed, 187 insertions(+), 10 deletions(-)

diff --git a/configure.ac b/configure.ac
index 6e48191e6..25c171170 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1537,6 +1537,7 @@ MIEXT_SHADOW_LIB='$(top_builddir)/miext/shadow/libshadow.la'
 MIEXT_SYNC_INC='-I$(top_srcdir)/miext/sync'
 MIEXT_SYNC_LIB='$(top_builddir)/miext/sync/libsync.la'
 CORE_INCS='-I$(top_srcdir)/include -I$(top_builddir)/include'
+AC_SUBST([MIEXT_SYNC_LIB])
 
 # SHA1 hashing
 AC_ARG_WITH([sha1],
diff --git a/glamor/Makefile.am b/glamor/Makefile.am
index 8c79994e0..29b488d22 100644
--- a/glamor/Makefile.am
+++ b/glamor/Makefile.am
@@ -2,6 +2,8 @@ noinst_LTLIBRARIES = libglamor.la libglamor_egl_stubs.la
 
 libglamor_la_LIBADD = $(GLAMOR_LIBS)
 
+libglamor_la_DEPENDENCIES = $(MIEXT_SYNC_LIB)
+
 AM_CFLAGS = $(CWARNFLAGS) $(DIX_CFLAGS) $(GLAMOR_CFLAGS)
 
 libglamor_la_SOURCES = \
diff --git a/glamor/glamor.c b/glamor/glamor.c
index 8b6b3f7de..4a9fef32f 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -260,6 +260,25 @@ _glamor_block_handler(ScreenPtr screen, void *timeout)
     screen->BlockHandler = _glamor_block_handler;
 }
 
+Bool
+glamor_support_fence(ScreenPtr screen, SyncFence *fence)
+{
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+
+    if (glamor_priv->flags & GLAMOR_USE_EGL_SCREEN)
+        return glamor_egl_support_fence(screen, fence);
+    return FALSE;
+}
+
+void
+glamor_add_fence(ScreenPtr screen, SyncFence *fence)
+{
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+
+    if (glamor_priv->flags & GLAMOR_USE_EGL_SCREEN)
+        glamor_egl_add_fence(screen, fence);
+}
+
 static void
 glamor_set_debug_level(int *debug_level)
 {
diff --git a/glamor/glamor.h b/glamor/glamor.h
index bfaf35f0d..628d82fac 100644
--- a/glamor/glamor.h
+++ b/glamor/glamor.h
@@ -35,6 +35,7 @@
 #include <picturestr.h>
 #include <fb.h>
 #include <fbpict.h>
+#include <misync.h>
 #ifdef GLAMOR_FOR_XORG
 #include <xf86xv.h>
 #endif
@@ -112,6 +113,9 @@ extern _X_EXPORT void glamor_set_pixmap_type(PixmapPtr pixmap,
                                              glamor_pixmap_type_t type);
 extern _X_EXPORT void glamor_block_handler(ScreenPtr screen);
 
+extern _X_EXPORT Bool glamor_support_fence(ScreenPtr screen, SyncFence *fence);
+extern _X_EXPORT void glamor_add_fence(ScreenPtr screen, SyncFence *fence);
+
 extern _X_EXPORT PixmapPtr glamor_create_pixmap(ScreenPtr screen, int w, int h,
                                                 int depth, unsigned int usage);
 extern _X_EXPORT Bool glamor_destroy_pixmap(PixmapPtr pixmap);
@@ -122,6 +126,9 @@ extern _X_EXPORT Bool glamor_destroy_pixmap(PixmapPtr pixmap);
 #define GLAMOR_CREATE_NO_LARGE          0x105
 #define GLAMOR_CREATE_PIXMAP_NO_TEXTURE 0x106
 
+extern _X_EXPORT Bool glamor_egl_support_fence(ScreenPtr screen, SyncFence *fence);
+extern _X_EXPORT Bool glamor_egl_add_fence(ScreenPtr screen, SyncFence *fence);
+
 /* @glamor_egl_exchange_buffers: Exchange the underlying buffers(KHR image,fbo).
  *
  * @front: front pixmap.
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index cb4f05ddf..043b69fdb 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -46,6 +46,7 @@
 #include "glamor.h"
 #include "glamor_priv.h"
 #include "dri3.h"
+#include "misync.h"
 
 struct glamor_egl_screen_private {
     EGLDisplay display;
@@ -93,6 +94,49 @@ glamor_egl_make_current(struct glamor_context *glamor_ctx)
     }
 }
 
+Bool
+glamor_egl_support_fence(ScreenPtr pScreen,
+                         SyncFence *fence)
+{
+    struct glamor_egl_screen_private *glamor_egl;
+
+    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(pScreen));
+    return (glamor_egl->dmafence_capable && fence != NULL &&
+            miSyncGetFenceType(fence) == SYNC_FENCE_DMA);
+}
+
+Bool
+glamor_egl_add_fence(ScreenPtr pScreen,
+                     SyncFence *fence)
+{
+    struct glamor_egl_screen_private *glamor_egl;
+    EGLSyncKHR sync;
+    EGLint attribs[3];
+    int i = 0;
+
+    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(pScreen));
+    if (!glamor_egl->dmafence_capable || fence == NULL)
+        return FALSE;
+
+    attribs[i++] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID;
+    attribs[i++] = miSyncTakeDMAFenceFDFromFence(pScreen, fence);
+    attribs[i++] = EGL_NONE;
+
+    if (!eglMakeCurrent(glamor_egl->display,
+                        EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context))
+        return FALSE;
+
+    sync = eglCreateSyncKHR(glamor_egl->display, EGL_SYNC_NATIVE_FENCE_ANDROID,
+                            attribs);
+    if (sync == EGL_NO_SYNC_KHR)
+        return FALSE;
+
+    eglWaitSyncKHR(glamor_egl->display, sync, 0);
+    eglDestroySyncKHR(glamor_egl->display, sync);
+
+    return TRUE;
+}
+
 static int
 glamor_get_flink_name(int fd, int handle, int *name)
 {
diff --git a/glamor/glamor_egl_stubs.c b/glamor/glamor_egl_stubs.c
index 4af1c13d5..3c8a5d634 100644
--- a/glamor/glamor_egl_stubs.c
+++ b/glamor/glamor_egl_stubs.c
@@ -42,3 +42,9 @@ glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
 {
     return 0;
 }
+
+Bool
+glamor_egl_add_fence(ScreenPtr screen, SyncFence *fence)
+{
+    return FALSE;
+}
diff --git a/hw/xfree86/drivers/modesetting/dri2.c b/hw/xfree86/drivers/modesetting/dri2.c
index bfaea3b84..b5e463d7e 100644
--- a/hw/xfree86/drivers/modesetting/dri2.c
+++ b/hw/xfree86/drivers/modesetting/dri2.c
@@ -494,7 +494,7 @@ ms_dri2_schedule_flip(ms_dri2_frame_event_ptr info)
     event->event_data = info->event_data;
 
     if (ms_do_pageflip(screen, back_priv->pixmap, event,
-                       drmmode_crtc->vblank_pipe, FALSE,
+                       drmmode_crtc->vblank_pipe, FALSE, NULL,
                        ms_dri2_flip_handler,
                        ms_dri2_flip_abort)) {
         ms->drmmode.dri2_flipping = TRUE;
diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h
index 09ffeea5e..e104c58fe 100644
--- a/hw/xfree86/drivers/modesetting/driver.h
+++ b/hw/xfree86/drivers/modesetting/driver.h
@@ -159,6 +159,7 @@ Bool ms_do_pageflip(ScreenPtr screen,
                     void *event,
                     int ref_crtc_vblank_pipe,
                     Bool async,
+                    SyncFence *in_fence,
                     ms_pageflip_handler_proc pageflip_handler,
                     ms_pageflip_abort_proc pageflip_abort);
 
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index e39009a17..1b30a55b7 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -419,7 +419,7 @@ drmmode_ConvertToKMode(ScrnInfoPtr scrn,
 
 int
 drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
-                    int x, int y, uint32_t flags, void *data)
+                    int x, int y, int in_fence_fd, uint32_t flags, void *data)
 {
     modesettingPtr ms = modesettingPTR(crtc->scrn);
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
@@ -480,6 +480,9 @@ drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
                               drmmode_crtc->mode_crtc->crtc_id);
         ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x);
         ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y);
+        if (in_fence_fd > -1)
+            ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_IN_FENCE_FD,
+                                  in_fence_fd);
 
         if (ret == 0)
             ret = drmModeAtomicCommit(ms->fd, req, flags, data);
@@ -1148,7 +1151,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
     }
 
     flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
-    if (drmmode_crtc_set_fb(crtc, mode, fb_id, x, y, flags, NULL)) {
+    if (drmmode_crtc_set_fb(crtc, mode, fb_id, x, y, -1, flags, NULL)) {
         xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
                    "failed to set mode: %s\n", strerror(errno));
         ret = FALSE;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 754cbedc2..847a2adbd 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -270,7 +270,7 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode,
 void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 
 int drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
-                        int x, int y, uint32_t flags, void *data);
+                        int x, int y, int fence_fd, uint32_t flags, void *data);
 
 Bool drmmode_support_dma_fences(ScrnInfoPtr pScrn);
 
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index 26738f928..a2c71d434 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -75,6 +75,7 @@ ms_flush_drm_events(ScreenPtr screen)
 struct ms_flipdata {
     ScreenPtr screen;
     void *event;
+    SyncFence *in_fence;
     ms_pageflip_handler_proc event_handler;
     ms_pageflip_abort_proc abort_handler;
     /* number of CRTC events referencing this */
@@ -108,6 +109,8 @@ ms_pageflip_free(struct ms_crtc_pageflip *flip)
     free(flip);
     if (--flipdata->flip_count > 0)
         return;
+    if (flipdata->in_fence)
+        miSyncDestroyFence(flipdata->in_fence);
     free(flipdata);
 }
 
@@ -161,15 +164,15 @@ ms_pageflip_abort(void *data)
 
 static Bool
 do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
-                      uint32_t flags, uint32_t seq)
+                      int fence_fd, uint32_t flags, uint32_t seq)
 {
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
 #ifdef GLAMOR_HAS_DRM_ATOMIC
     if (ms->atomic_modeset) {
         flags |= DRM_MODE_ATOMIC_NONBLOCK;
-        return drmmode_crtc_set_fb(crtc, NULL, ms->drmmode.fb_id, 0, 0, flags,
-                                   (void *) (uintptr_t) seq);
+        return drmmode_crtc_set_fb(crtc, NULL, ms->drmmode.fb_id, 0, 0, fence_fd,
+                                   flags, (void *) (uintptr_t) seq);
     }
 #endif
 
@@ -189,6 +192,7 @@ queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
     struct ms_crtc_pageflip *flip;
     uint32_t seq;
     int err;
+    int fence_fd = -1;
 
     flip = calloc(1, sizeof(struct ms_crtc_pageflip));
     if (flip == NULL) {
@@ -212,7 +216,10 @@ queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
     /* take a reference on flipdata for use in flip */
     flipdata->flip_count++;
 
-    while (do_queue_flip_on_crtc(ms, crtc, flags, seq)) {
+    if (flipdata->in_fence)
+        in_fence_fd = miSyncDMAFenceFDFromFence(screen, flipdata->in_fence);
+
+    while (do_queue_flip_on_crtc(ms, crtc, in_fence_fd, flags, seq)) {
         err = errno;
         /* We may have failed because the event queue was full.  Flush it
          * and retry.  If there was nothing to flush, then we failed for
@@ -241,6 +248,7 @@ ms_do_pageflip(ScreenPtr screen,
                void *event,
                int ref_crtc_vblank_pipe,
                Bool async,
+               SyncFence *in_fence,
                ms_pageflip_handler_proc pageflip_handler,
                ms_pageflip_abort_proc pageflip_abort)
 {
@@ -275,6 +283,7 @@ ms_do_pageflip(ScreenPtr screen,
 
     flipdata->event = event;
     flipdata->screen = screen;
+    flipdata->in_fence = in_fence;
     flipdata->event_handler = pageflip_handler;
     flipdata->abort_handler = pageflip_abort;
 
diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c
index be2af71dc..6d51ea58e 100644
--- a/hw/xfree86/drivers/modesetting/present.c
+++ b/hw/xfree86/drivers/modesetting/present.c
@@ -312,7 +312,47 @@ ms_present_flip(RRCrtcPtr crtc,
     event->unflip = FALSE;
 
     ret = ms_do_pageflip(screen, pixmap, event, drmmode_crtc->vblank_pipe, !sync_flip,
-                         ms_present_flip_handler, ms_present_flip_abort);
+                         NULL, ms_present_flip_handler, ms_present_flip_abort);
+    if (!ret)
+        xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n");
+    else
+        ms->drmmode.present_flipping = TRUE;
+
+    return ret;
+}
+
+static Bool
+ms_present_flip_with_fence(RRCrtcPtr crtc,
+                           uint64_t event_id,
+                           uint64_t target_msc,
+                           PixmapPtr pixmap,
+                           SyncFence *flip_fence,
+                           SyncFence *idle_fence,
+                           Bool sync_flip)
+{
+    ScreenPtr screen = crtc->pScreen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    modesettingPtr ms = modesettingPTR(scrn);
+    xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+    drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+    Bool ret;
+    struct ms_present_vblank_event *event;
+
+    if (!ms_present_check_flip(crtc, screen->root, pixmap, sync_flip))
+        return FALSE;
+
+    event = calloc(1, sizeof(struct ms_present_vblank_event));
+    if (!event)
+        return FALSE;
+
+    DebugPresent(("\t\tms:pf %lld msc %llu\n",
+                  (long long) event_id, (long long) target_msc));
+
+    event->event_id = event_id;
+    event->unflip = FALSE;
+
+    ret = ms_do_pageflip(screen, pixmap, event, drmmode_crtc->vblank_pipe, !sync_flip,
+                         flip_fence, ms_present_flip_handler, ms_present_flip_abort);
     if (!ret)
         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n");
     else
@@ -342,7 +382,7 @@ ms_present_unflip(ScreenPtr screen, uint64_t event_id)
     event->unflip = TRUE;
 
     if (ms_present_check_flip(NULL, screen->root, pixmap, TRUE) &&
-        ms_do_pageflip(screen, pixmap, event, -1, FALSE,
+        ms_do_pageflip(screen, pixmap, event, -1, FALSE, NULL,
                        ms_present_flip_handler, ms_present_flip_abort)) {
         return;
     }
@@ -373,6 +413,36 @@ ms_present_unflip(ScreenPtr screen, uint64_t event_id)
     present_event_notify(event_id, 0, 0);
     ms->drmmode.present_flipping = FALSE;
 }
+
+static Bool
+ms_present_can_wait(RRCrtcPtr crtc,
+                    SyncFence *fence)
+{
+#ifndef GLAMOR_HAS_DRM_ATOMIC
+    return FALSE;
+#else
+    ScreenPtr screen = crtc->pScreen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    modesettingPtr ms = modesettingPTR(scrn);
+
+    return (fence && miSyncGetFenceType(fence) == SYNC_FENCE_DMA &&
+            drmmode_support_dma_fences(scrn) &&
+            glamor_support_fence(screen, fence) &&
+            ms->atomic_modeset);
+#endif
+}
+
+/* Add a fence in the command stream
+ */
+static void
+ms_present_wait(RRCrtcPtr crtc,
+                SyncFence *fence)
+{
+    ScreenPtr screen = crtc->pScreen;
+
+    glamor_add_fence(screen, fence);
+}
+
 #endif
 
 static present_screen_info_rec ms_present_screen_info = {
@@ -388,7 +458,10 @@ static present_screen_info_rec ms_present_screen_info = {
 #ifdef GLAMOR_HAS_GBM
     .check_flip = ms_present_check_flip,
     .flip = ms_present_flip,
+    .flip_with_fence = ms_present_flip_with_fence,
     .unflip = ms_present_unflip,
+    .can_wait = ms_present_can_wait,
+    .wait = ms_present_wait,
 #endif
 };
 
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 06ea78f7e..528d1377b 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -536,6 +536,18 @@ glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
     return 0;
 }
 
+Bool
+glamor_egl_support_fence(ScreenPtr screen, SyncFence *fence)
+{
+   return FALSE;
+}
+
+Bool
+glamor_egl_add_fence(ScreenPtr screen, SyncFence *fence)
+{
+   return FALSE;
+}
+
 struct xwl_auth_state {
     int fd;
     ClientPtr client;
-- 
2.13.0



More information about the xorg-devel mailing list