[PATCH v7 02/11] randr/xf86: Add PRIME Synchronization / Double Buffer

Alex Goins agoins at nvidia.com
Fri Jun 17 03:06:47 UTC 2016


Changes PRIME to use double buffering and synchronization if all required
driver functions are available.

rrcrtc.c:
    Changes rrSetupPixmapSharing() to use double buffering and
    synchronization in the case that all required driver functions are
    available. Otherwise, falls back to unsynchronized single buffer.

    Changes RRCrtcDetachScanoutPixmap() to properly clean up in the case of
    double buffering.

    Moves StopPixmapTracking() from rrDestroySharedPixmap() to
    RRCrtcDetachScanoutPixmap().

    Changes RRReplaceScanoutPixmap() to fail if we are using double buffering,
    as it would need a second ppix parameter to function with double buffering,
    and AFAICT no driver I've implemented double buffered source support in uses
    RRReplaceScanoutPixmap().

randrstr.h:
    Adds scanout_pixmap_back to struct _rrCrtc to facilitate PRIME
    double buffering.

xf86Crtc.h:
    Adds current_scanout_back to _xf86Crtc to facilitate detection
    of changes to it in xf86RandR12CrtcSet().

xf86RandR12.c:
    Changes xf86RandR12CrtcSet() to detect changes in
    scanout_pixmap_back.

    Adds scanout_pixmap_back to struct _rrCrtc to facilitate PRIME double
    buffering.

v1: Initial commit
v2: Rename PresentTrackedFlippingPixmap to PresentSharedPixmap
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
    (rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
    Add fallback if flipping funcs fail
v4: Detach scanout pixmap when destroying scanout_pixmap_back, to avoid
    dangling pointers in some drivers
v5: Disable RRReplaceScanoutPixmap for double-buffered PRIME, it would need an
    ABI change with support for 2 pixmaps if it were to be supported, but AFAICT
    no driver that actually supports double-buffered PRIME uses it.
    Refactor to use rrEnableSharedPixmapFlipping() as a substitute for
    rrCrtcSetScanoutPixmap() in the flipping case.
    Remove extraneous pSlaveScrPriv from DetachScanoutPixmap()
    Remove extraneous protopix and pScrPriv from rrSetupPixmapSharing()
v6: Rebase onto ToT
v7: Unchanged

Signed-off-by: Alex Goins <agoins at nvidia.com>
---
 hw/xfree86/modes/xf86Crtc.h    |   4 ++
 hw/xfree86/modes/xf86RandR12.c |   4 +-
 randr/randrstr.h               |   1 +
 randr/rrcrtc.c                 | 131 ++++++++++++++++++++++++++++++++---------
 4 files changed, 111 insertions(+), 29 deletions(-)

diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index bdcfa13..8ab943c 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -392,6 +392,10 @@ struct _xf86Crtc {
     /* Added in ABI version 5
      */
     PixmapPtr current_scanout;
+
+    /* Added in ABI version 6
+     */
+    PixmapPtr current_scanout_back;
 };
 
 typedef struct _xf86OutputFuncs {
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index 60d2254..4828a61 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1154,7 +1154,8 @@ xf86RandR12CrtcSet(ScreenPtr pScreen,
     if (rotation != crtc->rotation)
         changed = TRUE;
 
-    if (crtc->current_scanout != randr_crtc->scanout_pixmap)
+    if (crtc->current_scanout != randr_crtc->scanout_pixmap ||
+        crtc->current_scanout_back != randr_crtc->scanout_pixmap_back)
         changed = TRUE;
 
     transform = RRCrtcGetTransform(randr_crtc);
@@ -1219,6 +1220,7 @@ xf86RandR12CrtcSet(ScreenPtr pScreen,
             xf86SaveModeContents(&crtc->desiredMode, &mode);
             crtc->desiredRotation = rotation;
             crtc->current_scanout = randr_crtc->scanout_pixmap;
+            crtc->current_scanout_back = randr_crtc->scanout_pixmap_back;
             if (transform) {
                 crtc->desiredTransform = *transform;
                 crtc->desiredTransformPresent = TRUE;
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 3e37df7..ada1348 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -130,6 +130,7 @@ struct _rrCrtc {
     struct pict_f_transform f_inverse;
 
     PixmapPtr scanout_pixmap;
+    PixmapPtr scanout_pixmap_back;
 };
 
 struct _rrOutput {
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index 5447133..da073b0 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -366,9 +366,6 @@ rrDestroySharedPixmap(RRCrtcPtr crtc, PixmapPtr pPixmap) {
     ScreenPtr master = crtc->pScreen->current_master;
 
     if (master && pPixmap->master_pixmap) {
-        PixmapPtr mscreenpix = master->GetScreenPixmap(master);
-
-        master->StopPixmapTracking(mscreenpix, pPixmap);
         /*
          * Unref the pixmap twice: once for the original reference, and once
          * for the reference implicitly added by PixmapShareToSlave.
@@ -387,11 +384,29 @@ RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
 {
     rrScrPriv(crtc->pScreen);
 
-    pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
     if (crtc->scanout_pixmap) {
+        ScreenPtr master = crtc->pScreen->current_master;
+        PixmapPtr mscreenpix = master->GetScreenPixmap(master);
+
+        if (crtc->scanout_pixmap_back) {
+            pScrPriv->rrDisableSharedPixmapFlipping(crtc);
+
+            master->StopFlippingPixmapTracking(mscreenpix,
+                                               crtc->scanout_pixmap,
+                                               crtc->scanout_pixmap_back);
+
+            rrDestroySharedPixmap(crtc, crtc->scanout_pixmap_back);
+            crtc->scanout_pixmap_back = NULL;
+        }
+        else {
+            pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
+            master->StopPixmapTracking(mscreenpix, crtc->scanout_pixmap);
+        }
+
         rrDestroySharedPixmap(crtc, crtc->scanout_pixmap);
+        crtc->scanout_pixmap = NULL;
     }
-    crtc->scanout_pixmap = NULL;
+
     RRCrtcChanged(crtc, TRUE);
 }
 
@@ -400,9 +415,7 @@ rrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master,
                      int width, int height, int depth,
                      int x, int y, Rotation rotation)
 {
-    Bool ret;
     PixmapPtr mpix, spix;
-    rrScrPriv(crtc->pScreen);
 
     mpix = master->CreatePixmap(master, width, height, depth,
                                 CREATE_PIXMAP_USAGE_SHARED);
@@ -415,13 +428,6 @@ rrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master,
         return NULL;
     }
 
-    ret = pScrPriv->rrCrtcSetScanoutPixmap(crtc, spix);
-    if (ret == FALSE) {
-        rrDestroySharedPixmap(crtc, spix);
-        ErrorF("randr: failed to set shadow slave pixmap\n");
-        return NULL;
-    }
-
     return spix;
 }
 
@@ -430,16 +436,30 @@ rrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height,
                      int x, int y, Rotation rotation)
 {
     ScreenPtr master = crtc->pScreen->current_master;
+    rrScrPrivPtr pMasterScrPriv = rrGetScrPriv(master);
+    rrScrPrivPtr pSlaveScrPriv = rrGetScrPriv(crtc->pScreen);
+
     int depth;
     PixmapPtr mscreenpix;
-    PixmapPtr spix;
-
-    /* create a pixmap on the master screen,
-       then get a shared handle for it
-       create a shared pixmap on the slave screen using the handle
-       set the master screen to do dirty updates to the shared pixmap
-       from the screen pixmap.
-       set slave screen to scanout shared linear pixmap
+    PixmapPtr spix_front;
+
+    /* Create a pixmap on the master screen, then get a shared handle for it.
+       Create a shared pixmap on the slave screen using the handle.
+
+       If sync == FALSE --
+       Set slave screen to scanout shared linear pixmap.
+       Set the master screen to do dirty updates to the shared pixmap
+       from the screen pixmap on its own accord.
+
+       If sync == TRUE --
+       If any of the below steps fail, clean up and fall back to sync == FALSE.
+       Create another shared pixmap on the slave screen using the handle.
+       Set slave screen to prepare for scanout and flipping between shared
+       linear pixmaps.
+       Set the master screen to do dirty updates to the shared pixmaps from the
+       screen pixmap when prompted to by us or the slave.
+       Prompt the master to do a dirty update on the first shared pixmap, then
+       defer to the slave.
     */
 
     mscreenpix = master->GetScreenPixmap(master);
@@ -452,16 +472,65 @@ rrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height,
         return TRUE;
     }
 
-    spix = rrCreateSharedPixmap(crtc, master,
-                                width, height, depth,
-                                x, y, rotation);
-    if (spix == NULL) {
+    spix_front = rrCreateSharedPixmap(crtc, master,
+                                      width, height, depth,
+                                      x, y, rotation);
+    if (spix_front == NULL) {
         return FALSE;
     }
 
-    crtc->scanout_pixmap = spix;
+    /* Both source and sink must support required ABI funcs for flipping */
+    if (pSlaveScrPriv->rrEnableSharedPixmapFlipping &&
+        pSlaveScrPriv->rrDisableSharedPixmapFlipping &&
+        pMasterScrPriv->rrStartFlippingPixmapTracking &&
+        master->PresentSharedPixmap &&
+        master->StopFlippingPixmapTracking) {
+
+        PixmapPtr spix_back = rrCreateSharedPixmap(crtc, master,
+                                                   width, height, depth,
+                                                   x, y, rotation);
+        if (spix_back == NULL)
+            goto fail;
+
+        if (!pSlaveScrPriv->rrEnableSharedPixmapFlipping(crtc,
+                                                         spix_front, spix_back))
+            goto fail;
+
+        crtc->scanout_pixmap = spix_front;
+        crtc->scanout_pixmap_back = spix_back;
+
+        if (!pMasterScrPriv->rrStartFlippingPixmapTracking(crtc, mscreenpix,
+                                                           spix_front,
+                                                           spix_back,
+                                                           x, y, 0, 0,
+                                                           rotation)) {
+            pSlaveScrPriv->rrDisableSharedPixmapFlipping(crtc);
+            goto fail;
+        }
+
+        master->PresentSharedPixmap(spix_front);
+
+        return TRUE;
+
+fail: /* If flipping funcs fail, just fall back to unsynchronized */
+        if (spix_back)
+            rrDestroySharedPixmap(crtc, spix_back);
+
+        crtc->scanout_pixmap = NULL;
+        crtc->scanout_pixmap_back = NULL;
+    }
+
+    ErrorF("randr: falling back to unsynchronized pixmap sharing\n");
+
+    if (!pSlaveScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) {
+        rrDestroySharedPixmap(crtc, spix_front);
+        ErrorF("randr: failed to set shadow slave pixmap\n");
+        return FALSE;
+    }
+    crtc->scanout_pixmap = spix_front;
+
+    master->StartPixmapTracking(mscreenpix, spix_front, x, y, 0, 0, rotation);
 
-    master->StartPixmapTracking(mscreenpix, spix, x, y, 0, 0, rotation);
     return TRUE;
 }
 
@@ -1741,6 +1810,12 @@ RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
         if (!crtc->scanout_pixmap && !enable)
             continue;
 
+        /* not supported with double buffering, needs ABI change for 2 ppix */
+        if (crtc->scanout_pixmap_back) {
+            ret = FALSE;
+            continue;
+        }
+
         size_fits = (crtc->mode &&
                      crtc->x == pDrawable->x &&
                      crtc->y == pDrawable->y &&
-- 
1.9.1



More information about the xorg-devel mailing list