[RFC xserver 07/12] present: Allow present implementations to wait on fences

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


Instead of relying on the present module to wait on in-fences,
we added some hooks to allow the drivers/hardware to do the work.
Drivers need to implement can_wait, wait and flip_with_fence
to handle it.

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
---
 present/present.c       | 51 +++++++++++++++++++++++++++++++++++++++----------
 present/present.h       | 23 +++++++++++++++++++++-
 present/present_fence.c |  8 ++++++++
 present/present_priv.h  |  3 +++
 4 files changed, 74 insertions(+), 11 deletions(-)

diff --git a/present/present.c b/present/present.c
index 70cbad8f8..69307f6e0 100644
--- a/present/present.c
+++ b/present/present.c
@@ -188,16 +188,34 @@ present_check_flip(RRCrtcPtr    crtc,
 }
 
 static Bool
-present_flip(RRCrtcPtr crtc,
-             uint64_t event_id,
-             uint64_t target_msc,
-             PixmapPtr pixmap,
-             Bool sync_flip)
+present_flip(present_vblank_ptr vblank)
 {
-    ScreenPtr                   screen = crtc->pScreen;
+    ScreenPtr                   screen = vblank->crtc->pScreen;
     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
 
-    return (*screen_priv->info->flip) (crtc, event_id, target_msc, pixmap, sync_flip);
+    if (vblank->wait_fence &&
+        screen_priv->info->flip_with_fence != NULL) {
+        Bool ret;
+
+        ret = (*screen_priv->info->flip_with_fence) (vblank->crtc,
+                                                     vblank->event_id,
+                                                     vblank->target_msc,
+                                                     vblank->pixmap,
+                                                     present_fence_get_fence(vblank->wait_fence),
+                                                     vblank->sync_flip);
+
+        return ret;
+    } else if (vblank->wait_fence) {
+        if (!present_fence_check_triggered(vblank->wait_fence)) {
+           /* The can_wait() hook should have returned FALSE before we tried to
+            * flip with an untriggered wait fence */
+           return FALSE;
+        }
+    }
+
+    return (*screen_priv->info->flip) (vblank->crtc, vblank->event_id,
+                                       vblank->target_msc, vblank->pixmap,
+                                       vblank->sync_flip);
 }
 
 static void
@@ -486,7 +504,8 @@ present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
 
     assert (vblank == screen_priv->flip_pending);
 
-    present_flip_idle(screen);
+    if (!vblank->notify_fence)
+        present_flip_idle(screen);
 
     xorg_list_del(&vblank->event_queue);
 
@@ -632,6 +651,7 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
     ScreenPtr                   screen = window->drawable.pScreen;
     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
     uint8_t                     mode;
+    Bool                        wait = FALSE;
 
     if (vblank->requeue) {
         vblank->requeue = FALSE;
@@ -644,7 +664,11 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
     }
 
     if (vblank->wait_fence) {
-        if (!present_fence_check_triggered(vblank->wait_fence)) {
+        /* Check if present implementation can wait for the fence itself */
+        if (screen_priv->info->can_wait &&
+            (*screen_priv->info->can_wait) (vblank->crtc, present_fence_get_fence(vblank->wait_fence))) {
+            wait = TRUE;
+        } else if (!present_fence_check_triggered(vblank->wait_fence)) {
             present_fence_set_callback(vblank->wait_fence, present_wait_fence_triggered, vblank);
             return;
         }
@@ -682,7 +706,7 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
             xorg_list_add(&vblank->event_queue, &present_flip_queue);
             /* Try to flip
              */
-            if (present_flip(vblank->crtc, vblank->event_id, vblank->target_msc, vblank->pixmap, vblank->sync_flip)) {
+            if (present_flip(vblank)) {
                 RegionPtr damage;
 
                 /* Fix window pixmaps:
@@ -742,6 +766,13 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
             return;
         }
 
+        if (wait) {
+            (*screen_priv->info->wait)(vblank->crtc,
+                                       present_fence_get_fence(vblank->wait_fence));
+            present_fence_destroy(vblank->wait_fence);
+            vblank->wait_fence = NULL;
+        }
+
         present_copy_region(&window->drawable, vblank->pixmap, vblank->update, vblank->x_off, vblank->y_off);
 
         /* present_copy_region sticks the region into a scratch GC,
diff --git a/present/present.h b/present/present.h
index aab2e168a..0d5d72652 100644
--- a/present/present.h
+++ b/present/present.h
@@ -25,6 +25,7 @@
 
 #include <X11/extensions/presentproto.h>
 #include "randrstr.h"
+#include "misync.h"
 #include "presentext.h"
 
 typedef struct present_vblank present_vblank_rec, *present_vblank_ptr;
@@ -76,6 +77,13 @@ typedef Bool (*present_flip_ptr) (RRCrtcPtr crtc,
                                   PixmapPtr pixmap,
                                   Bool sync_flip);
 
+typedef Bool (*present_flip_with_fence_ptr) (RRCrtcPtr crtc,
+                                             uint64_t event_id,
+                                             uint64_t target_msc,
+                                             PixmapPtr pixmap,
+                                             SyncFence *wait_fence,
+                                             Bool sync_flip);
+
 /* "unflip" back to the regular screen scanout buffer
  *
  * present_event_notify should be called with 'event_id' when the unflip occurs.
@@ -83,7 +91,17 @@ typedef Bool (*present_flip_ptr) (RRCrtcPtr crtc,
 typedef void (*present_unflip_ptr) (ScreenPtr screen,
                                     uint64_t event_id);
 
-#define PRESENT_SCREEN_INFO_VERSION        0
+/* Return whether the fence can be waited upon
+ */
+typedef Bool (*present_can_wait_ptr) (RRCrtcPtr crtc,
+                                      SyncFence *fence);
+
+/* Wait for the fence to be triggered
+ */
+typedef void (*present_wait_ptr) (RRCrtcPtr crtc,
+                                  SyncFence *fence);
+
+#define PRESENT_SCREEN_INFO_VERSION        1
 
 typedef struct present_screen_info {
     uint32_t                            version;
@@ -97,6 +115,9 @@ typedef struct present_screen_info {
     present_check_flip_ptr              check_flip;
     present_flip_ptr                    flip;
     present_unflip_ptr                  unflip;
+    present_flip_with_fence_ptr         flip_with_fence;
+    present_can_wait_ptr                can_wait;
+    present_wait_ptr                    wait;
 
 } present_screen_info_rec, *present_screen_info_ptr;
 
diff --git a/present/present_fence.c b/present/present_fence.c
index e09657d31..b7512df88 100644
--- a/present/present_fence.c
+++ b/present/present_fence.c
@@ -91,6 +91,14 @@ present_fence_create(SyncFence *fence)
     return present_fence;
 }
 
+SyncFence *
+present_fence_get_fence(struct present_fence *present_fence)
+{
+    if (present_fence)
+        return present_fence->fence;
+    return NULL;
+}
+
 void
 present_fence_destroy(struct present_fence *present_fence)
 {
diff --git a/present/present_priv.h b/present/present_priv.h
index dfb4bdea9..c742c48a8 100644
--- a/present/present_priv.h
+++ b/present/present_priv.h
@@ -253,6 +253,9 @@ present_fake_queue_init(void);
 struct present_fence *
 present_fence_create(SyncFence *sync_fence);
 
+SyncFence *
+present_fence_get_fence(struct present_fence *present_fence);
+
 void
 present_fence_destroy(struct present_fence *present_fence);
 
-- 
2.13.0



More information about the xorg-devel mailing list