[RFC xserver v5 04/14] present: Send PresentCompleteModeSuboptimalCopy appropriately

Louis-Francis Ratté-Boulianne lfrb at collabora.com
Mon Nov 6 21:30:42 UTC 2017


Add 'check_flip2' hook for driver to let know the core
about why flipping is not possible ('reason').
If it is because of unsupported buffer format/modifier,
a PresentCompleteNotify event is sent to the client with
the PresentCompleteModeSuboptimalCopy mode.

v2: Check for PresentOptionSuboptimal and check driver version
    before using 'check_flip2'.

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
---
 configure.ac                |  2 +-
 include/protocol-versions.h |  2 +-
 present/meson.build         |  2 +-
 present/present.c           | 35 +++++++++++++++++++++++++----------
 present/present.h           | 10 +++++++++-
 present/present_priv.h      |  2 ++
 6 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/configure.ac b/configure.ac
index 342b07f94..7fb1c99ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -755,7 +755,7 @@ DAMAGEPROTO="damageproto >= 1.1"
 XCMISCPROTO="xcmiscproto >= 1.2.0"
 BIGREQSPROTO="bigreqsproto >= 1.1.0"
 XTRANS="xtrans >= 1.3.5"
-PRESENTPROTO="presentproto >= 1.0"
+PRESENTPROTO="presentproto >= 1.1"
 
 dnl List of libraries that require a specific version
 LIBAPPLEWM="applewm >= 1.4"
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index b4498927b..fd8d8df88 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -69,7 +69,7 @@
 
 /* Present */
 #define SERVER_PRESENT_MAJOR_VERSION            1
-#define SERVER_PRESENT_MINOR_VERSION            0
+#define SERVER_PRESENT_MINOR_VERSION            1
 
 /* RandR */
 #define SERVER_RANDR_MAJOR_VERSION		1
diff --git a/present/meson.build b/present/meson.build
index a4296ca7a..cf725302a 100644
--- a/present/meson.build
+++ b/present/meson.build
@@ -13,7 +13,7 @@ libxserver_present = static_library('libxserver_present',
     include_directories: inc,
     dependencies: [
         common_dep,
-        dependency('presentproto', version: '>= 1.0')
+        dependency('presentproto', version: '>= 1.1')
     ],
     c_args: '-DHAVE_XORG_CONFIG_H'
 )
diff --git a/present/present.c b/present/present.c
index 176e89c0b..1eda1e6ee 100644
--- a/present/present.c
+++ b/present/present.c
@@ -124,7 +124,8 @@ present_check_flip(RRCrtcPtr    crtc,
                    Bool         sync_flip,
                    RegionPtr    valid,
                    int16_t      x_off,
-                   int16_t      y_off)
+                   int16_t      y_off,
+                   int         *reason)
 {
     ScreenPtr                   screen = window->drawable.pScreen;
     PixmapPtr                   window_pixmap;
@@ -177,7 +178,12 @@ present_check_flip(RRCrtcPtr    crtc,
     }
 
     /* Ask the driver for permission */
-    if (screen_priv->info->check_flip) {
+    if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2 && reason) {
+        if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
+            DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
+            return FALSE;
+        }
+    } else if (screen_priv->info->check_flip) {
         if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
             DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
             return FALSE;
@@ -564,6 +570,7 @@ present_check_flip_window (WindowPtr window)
     present_window_priv_ptr     window_priv = present_window_priv(window);
     present_vblank_ptr          flip_pending = screen_priv->flip_pending;
     present_vblank_ptr          vblank;
+    int                         reason;
 
     /* If this window hasn't ever been used with Present, it can't be
      * flipping
@@ -580,7 +587,7 @@ present_check_flip_window (WindowPtr window)
          */
         if (flip_pending->window == window) {
             if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
-                                    flip_pending->sync_flip, NULL, 0, 0))
+                                    flip_pending->sync_flip, NULL, 0, 0, NULL))
                 present_set_abort_flip(screen);
         }
     } else {
@@ -588,15 +595,16 @@ present_check_flip_window (WindowPtr window)
          * Check current flip
          */
         if (window == screen_priv->flip_window) {
-            if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0))
+            if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0, NULL))
                 present_unflip(screen);
         }
     }
 
     /* Now check any queued vblanks */
     xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
-        if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0)) {
+        if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) {
             vblank->flip = FALSE;
+            vblank->reason = reason;
             if (vblank->sync_flip)
                 vblank->requeue = TRUE;
         }
@@ -756,10 +764,14 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
     /* Compute correct CompleteMode
      */
     if (vblank->kind == PresentCompleteKindPixmap) {
-        if (vblank->pixmap && vblank->window)
-            mode = PresentCompleteModeCopy;
-        else
+        if (vblank->pixmap && vblank->window) {
+            if (vblank->has_suboptimal && vblank->reason == PresentFlipReasonBufferFormat)
+                mode = PresentCompleteModeSuboptimalCopy;
+            else
+                mode = PresentCompleteModeCopy;
+        } else {
             mode = PresentCompleteModeSkip;
+        }
     }
     else
         mode = PresentCompleteModeCopy;
@@ -795,6 +807,7 @@ present_pixmap(WindowPtr window,
     ScreenPtr                   screen = window->drawable.pScreen;
     present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+    int                         reason = 0;
 
     if (!window_priv)
         return BadAlloc;
@@ -912,22 +925,24 @@ present_pixmap(WindowPtr window,
     vblank->msc_offset = window_priv->msc_offset;
     vblank->notifies = notifies;
     vblank->num_notifies = num_notifies;
+    vblank->has_suboptimal = (options & PresentOptionSuboptimal);
 
     if (pixmap != NULL &&
         !(options & PresentOptionCopy) &&
         screen_priv->info) {
         if (msc_is_after(target_msc, crtc_msc) &&
-            present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off))
+            present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason))
         {
             vblank->flip = TRUE;
             vblank->sync_flip = TRUE;
             target_msc--;
         } else if ((screen_priv->info->capabilities & PresentCapabilityAsync) &&
-            present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off))
+            present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason))
         {
             vblank->flip = TRUE;
         }
     }
+    vblank->reason = reason;
 
     if (wait_fence) {
         vblank->wait_fence = present_fence_create(wait_fence);
diff --git a/present/present.h b/present/present.h
index aab2e168a..094946a7c 100644
--- a/present/present.h
+++ b/present/present.h
@@ -27,6 +27,9 @@
 #include "randrstr.h"
 #include "presentext.h"
 
+#define PresentFlipReasonUnknown       0
+#define PresentFlipReasonBufferFormat  1
+
 typedef struct present_vblank present_vblank_rec, *present_vblank_ptr;
 
 /* Return the current CRTC for 'window'.
@@ -59,6 +62,10 @@ typedef void (*present_flush_ptr) (WindowPtr window);
  */
 typedef Bool (*present_check_flip_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip);
 
+/* Same as 'check_flip' but it can return a 'reason' why the flip would fail.
+ */
+typedef Bool (*present_check_flip2_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip, int *reason);
+
 /* Flip pixmap, return false if it didn't happen.
  *
  * 'crtc' is to be used for any necessary synchronization.
@@ -83,7 +90,7 @@ typedef Bool (*present_flip_ptr) (RRCrtcPtr crtc,
 typedef void (*present_unflip_ptr) (ScreenPtr screen,
                                     uint64_t event_id);
 
-#define PRESENT_SCREEN_INFO_VERSION        0
+#define PRESENT_SCREEN_INFO_VERSION        1
 
 typedef struct present_screen_info {
     uint32_t                            version;
@@ -97,6 +104,7 @@ typedef struct present_screen_info {
     present_check_flip_ptr              check_flip;
     present_flip_ptr                    flip;
     present_unflip_ptr                  unflip;
+    present_check_flip2_ptr             check_flip2;
 
 } present_screen_info_rec, *present_screen_info_ptr;
 
diff --git a/present/present_priv.h b/present/present_priv.h
index dfb4bdea9..2fb9a2344 100644
--- a/present/present_priv.h
+++ b/present/present_priv.h
@@ -75,6 +75,8 @@ struct present_vblank {
     Bool                flip_ready;     /* wants to flip, but waiting for previous flip or unflip */
     Bool                sync_flip;      /* do flip synchronous to vblank */
     Bool                abort_flip;     /* aborting this flip */
+    int                 reason;         /* reason for which flip is not possible */
+    Bool                has_suboptimal; /* whether client can support SuboptimalCopy mode */
 };
 
 typedef struct present_screen_priv {
-- 
2.13.0



More information about the xorg-devel mailing list