[PATCH v6 07/11] modesetting: Implement PRIME syncing as a sink

Alex Goins agoins at nvidia.com
Sat Jun 11 00:21:01 UTC 2016


Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.

Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.

Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.

driver.c:
    Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
    SharedPixmapNotifyDamage.

    Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
    same but flushes damage associated with a ppriv instead of the crtc, and
    chanage dispatch_slave_dirty to use it on both scanout pixmaps if
    applicable.

drmmode_display.h:
    Add flip_seq field to msPixmapPrivRec to keep track of the event handler
    associated with a given pixmap, if any.

    Add wait_for_damage field to msPixmapPrivRec to keep track if we have
    requested a damage notification from the source.

    Add enable_flipping field to drmmode_crtc_private_rec to keep track if
    flipping is enabled or disabled.

    Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
    buffer internally.

    Add declarations for drmmode_SetupPageFlipFence(),
    drmmode_EnableSharedPixmapFlipping(),
    drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
    drmmode_SharedPixmapPresentOnVBlank().

    Move slave damage from crtc to ppriv.

drmmode_display.c:
    Change drmmode_set_scanout_pixmap*() functions to
    drmmode_set_target_scanout_pixmap*() that take an additional parameter
    PixmapPtr *target for explicitly setting different scanout pixmaps.

    Add definitions for functions drmmode_SharedPixmapFlip(),
    drmmode_SharedPixmapPresentOnVBlank(),
    drmmode_SharedPixmapPresent(),
    drmmode_SharedPixmapVBlankEventHandler(),
    drmmode_SharedPixmapVBlankEventAbort(),
    drmmode_EnableSharedPixmapFlipping(), and
    drmmode_DisableSharedPixmapFlipping,
    drmmode_InitSharedPixmapFlipping(), and
    drmmode_FiniSharedPixmapFlipping, along with struct
    vblank_event_args.

    The control flow is as follows:
        pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
        drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
        TRUE and sets both scanout pixmaps prime_pixmap and
        prime_pixmap_back.

        When setting a mode, if prime_pixmap is defined, modesetting
        driver will call drmmode_InitSharedPixmapFlipping(), which if
        flipping is enabled will call drmmode_SharedPixmapPresent() on
        scanout_pixmap_back.

        drmmode_SharedPixmapPresent() requests that for the source to
        present on the given buffer using master->PresentSharedPixmap(). If
        it succeeds, it will then attempt to flip to that buffer using
        drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
        does, it will raise a warning and try drmmode_SharedPixmapPresent()
        again on the next vblank using
        drmmode_SharedPixmapPresentOnVBlank().

        master->PresentSharedPixmap() could fail, in most cases because
        there is no outstanding damage on the mscreenpix tracked by the
        shared pixmap. In this case, drmmode_SharedPixmapPresent() will
        attempt to use master->RequestSharedPixmapNotifyDamage() to request
        for the source driver to call slave->SharedPixmapNotifyDamage() in
        response to damage on mscreenpix. This will ultimately call
        into drmmode_SharedPixmapPresentOnVBlank() to retry
        drmmode_SharedPixmapPresent() on the next vblank after
        accumulating damage.

        drmmode_SharedPixmapFlip() sets up page flip event handler by
        packing struct vblank_event_args with the necessary parameters, and
        registering drmmode_SharedPixmapVBlankEventHandler() and
        drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
        event handler queue. Then, it uses the drmModePageFlip() to flip on
        the next vblank and raise an event.

        drmmode_SharedPixmapPresentOnVBlank() operates similarly to
        drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
        drmModePageFlip() to raise the event without flipping.

        On the next vblank, DRM will raise an event that will ultimately be
        handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
        it will update prime_pixmap and prime_pixmap_back to reflect that
        frontTarget is now being displayed, and use
        drmmode_SharedPixmapPresent(backTarget) to start the process again
        on the now-hidden shared pixmap. If we didn't flip, it will just
        use drmmode_SharedPixmapPresent(frontTarget) to start the process
        again on the still-hidden shared pixmap.

        Note that presentation generally happens asynchronously, so with
        these changes alone tearing is reduced, but we can't always
        guarantee that the present will finish before the flip. These
        changes are meant to be paired with changes to the sink DRM driver
        that makes flips wait on fences attached to dmabuf backed buffers.
        The source driver is responsible for attaching the fences and
        signaling them when presentation is finished.

        Note that because presentation is requested in response to a
        vblank, PRIME sources will now conform to the sink's refresh rate.

        At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
        called, making its way to drmmode_FiniSharedPixmapFlipping().
        There, the event handlers for prime_pixmap and prime_pixmap_back
        are aborted, freeing the left over parameter structure. Then,
        prime_pixmap and prime_pixmap back are unset as scanout pixmaps.

    Register and tear down slave damage per-scanout pixmap instead of
    per-crtc.

v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
    Renamed flipSeq to flip_seq
    Warn if flip failed
    Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
    (rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
    Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
    Move disabling for reverse PRIME from source commit to here
    Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
    internally to EnableSharedPixmapFlipping().
    Don't support flipping if ms->drmmode.pageflip == FALSE.
    Move flipping_active check to this commit
v6: Rebase onto ToT

Signed-off-by: Alex Goins <agoins at nvidia.com>
---
 hw/xfree86/drivers/modesetting/driver.c          |  96 +++++++-
 hw/xfree86/drivers/modesetting/drmmode_display.c | 298 +++++++++++++++++++++--
 hw/xfree86/drivers/modesetting/drmmode_display.h |  19 +-
 3 files changed, 375 insertions(+), 38 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index 97a7404..ab3b028 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -529,20 +529,14 @@ dispatch_dirty(ScreenPtr pScreen)
 }
 
 static void
-dispatch_dirty_crtc(ScrnInfoPtr scrn, xf86CrtcPtr crtc)
+dispatch_dirty_pixmap(ScrnInfoPtr scrn, xf86CrtcPtr crtc, PixmapPtr ppix)
 {
     modesettingPtr ms = modesettingPTR(scrn);
-    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-    PixmapPtr pixmap = drmmode_crtc->prime_pixmap;
-    DamagePtr damage = drmmode_crtc->slave_damage;
-    msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, pixmap);
+    msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix);
+    DamagePtr damage = ppriv->slave_damage;
     int fb_id = ppriv->fb_id;
-    int ret;
-
-    ret = dispatch_dirty_region(scrn, pixmap, damage, fb_id);
-    if (ret) {
 
-    }
+    dispatch_dirty_region(scrn, ppix, damage, fb_id);
 }
 
 static void
@@ -558,10 +552,11 @@ dispatch_slave_dirty(ScreenPtr pScreen)
 
         if (!drmmode_crtc)
             continue;
-        if (!drmmode_crtc->prime_pixmap)
-            continue;
 
-        dispatch_dirty_crtc(scrn, crtc);
+        if (drmmode_crtc->prime_pixmap)
+            dispatch_dirty_pixmap(scrn, crtc, drmmode_crtc->prime_pixmap);
+        if (drmmode_crtc->prime_pixmap_back)
+            dispatch_dirty_pixmap(scrn, crtc, drmmode_crtc->prime_pixmap_back);
     }
 }
 
@@ -973,9 +968,45 @@ msUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
 }
 
 static Bool
+msEnableSharedPixmapFlipping(RRCrtcPtr crtc, PixmapPtr front, PixmapPtr back)
+{
+    ScreenPtr screen = crtc->pScreen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    modesettingPtr ms = modesettingPTR(scrn);
+    xf86CrtcPtr xf86Crtc = crtc->devPrivate;
+
+    if (!xf86Crtc)
+        return FALSE;
+
+    /* Not supported if we can't flip */
+    if (!ms->drmmode.pageflip)
+        return FALSE;
+
+    /* Not currently supported with reverse PRIME */
+    if (ms->drmmode.reverse_prime_offload_mode)
+        return FALSE;
+
+    return drmmode_EnableSharedPixmapFlipping(xf86Crtc, &ms->drmmode,
+                                              front, back);
+}
+
+static void
+msDisableSharedPixmapFlipping(RRCrtcPtr crtc)
+{
+    ScreenPtr screen = crtc->pScreen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    modesettingPtr ms = modesettingPTR(scrn);
+    xf86CrtcPtr xf86Crtc = crtc->devPrivate;
+
+    if (xf86Crtc)
+        drmmode_DisableSharedPixmapFlipping(xf86Crtc, &ms->drmmode);
+}
+
+static Bool
 CreateScreenResources(ScreenPtr pScreen)
 {
     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+    rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen);
     modesettingPtr ms = modesettingPTR(pScrn);
     PixmapPtr rootPixmap;
     Bool ret;
@@ -1034,6 +1065,10 @@ CreateScreenResources(ScreenPtr pScreen)
             return FALSE;
         }
     }
+
+    pScrPriv->rrEnableSharedPixmapFlipping = msEnableSharedPixmapFlipping;
+    pScrPriv->rrDisableSharedPixmapFlipping = msDisableSharedPixmapFlipping;
+
     return ret;
 }
 
@@ -1097,6 +1132,39 @@ msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle)
 }
 
 static Bool
+msSharedPixmapNotifyDamage(PixmapPtr ppix)
+{
+    Bool ret = FALSE;
+    int c;
+
+    ScreenPtr screen = ppix->drawable.pScreen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    modesettingPtr ms = modesettingPTR(scrn);
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+
+    msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix);
+
+    if (!ppriv->wait_for_damage)
+        return ret;
+    ppriv->wait_for_damage = FALSE;
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr crtc = xf86_config->crtc[c];
+        drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+        if (!drmmode_crtc)
+            continue;
+        if (!(drmmode_crtc->prime_pixmap && drmmode_crtc->prime_pixmap_back))
+            continue;
+
+        // Received damage on master screen pixmap, schedule present on vblank
+        ret |= drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, &ms->drmmode);
+    }
+
+    return ret;
+}
+
+static Bool
 SetMaster(ScrnInfoPtr pScrn)
 {
     modesettingPtr ms = modesettingPTR(pScrn);
@@ -1260,6 +1328,8 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv)
     pScreen->StartPixmapTracking = PixmapStartDirtyTracking;
     pScreen->StopPixmapTracking = PixmapStopDirtyTracking;
 
+    pScreen->SharedPixmapNotifyDamage = msSharedPixmapNotifyDamage;
+
     if (!xf86CrtcScreenInit(pScreen))
         return FALSE;
 
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index da577e5..0720103 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -229,6 +229,239 @@ drmmode_SetSlaveBO(PixmapPtr ppix,
     return TRUE;
 }
 
+static Bool
+drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc,
+                            drmmode_ptr drmmode)
+{
+    ScreenPtr master = crtc->randr_crtc->pScreen->current_master;
+
+    if (master->PresentSharedPixmap(ppix)) {
+        /* Success, queue flip to back target */
+        if (drmmode_SharedPixmapFlip(ppix, crtc, drmmode))
+            return TRUE;
+
+        xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
+                   "drmmode_SharedPixmapFlip() failed, trying again next vblank\n");
+
+        return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
+    }
+
+    /* Failed to present, try again on next vblank after damage */
+    if (master->RequestSharedPixmapNotifyDamage) {
+        msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
+
+        /* Set flag first in case we are immediately notified */
+        ppriv->wait_for_damage = TRUE;
+
+        if (master->RequestSharedPixmapNotifyDamage(ppix))
+            return TRUE;
+        else
+            ppriv->wait_for_damage = FALSE;
+    }
+
+    /* Damage notification not available, just try again on vblank */
+    return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
+}
+
+struct vblank_event_args {
+    PixmapPtr frontTarget;
+    PixmapPtr backTarget;
+    xf86CrtcPtr crtc;
+    drmmode_ptr drmmode;
+    Bool flip;
+};
+static void
+drmmode_SharedPixmapVBlankEventHandler(uint64_t frame, uint64_t usec,
+                                       void *data)
+{
+    struct vblank_event_args *args = data;
+
+    drmmode_crtc_private_ptr drmmode_crtc = args->crtc->driver_private;
+
+    if (args->flip) {
+        /* frontTarget is being displayed, update crtc to reflect */
+        drmmode_crtc->prime_pixmap = args->frontTarget;
+        drmmode_crtc->prime_pixmap_back = args->backTarget;
+
+        /* Safe to present on backTarget, no longer displayed */
+        drmmode_SharedPixmapPresent(args->backTarget, args->crtc, args->drmmode);
+    } else {
+        /* backTarget is still being displayed, present on frontTarget */
+        drmmode_SharedPixmapPresent(args->frontTarget, args->crtc, args->drmmode);
+    }
+
+    free(args);
+}
+
+static void
+drmmode_SharedPixmapVBlankEventAbort(void *data)
+{
+    struct vblank_event_args *args = data;
+
+    msGetPixmapPriv(args->drmmode, args->frontTarget)->flip_seq = 0;
+
+    free(args);
+}
+
+Bool
+drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix, xf86CrtcPtr crtc,
+                                    drmmode_ptr drmmode)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
+
+    drmVBlank vbl;
+    struct vblank_event_args *event_args;
+
+    if (ppix == drmmode_crtc->prime_pixmap)
+        return FALSE; /* Already flipped to this pixmap */
+    if (ppix != drmmode_crtc->prime_pixmap_back)
+        return FALSE; /* Pixmap is not a scanout pixmap for CRTC */
+
+    event_args = calloc(1, sizeof(*event_args));
+    if (!event_args)
+        return FALSE;
+
+    event_args->frontTarget = ppix;
+    event_args->backTarget = drmmode_crtc->prime_pixmap;
+    event_args->crtc = crtc;
+    event_args->drmmode = drmmode;
+    event_args->flip = FALSE;
+
+    ppriv->flip_seq =
+        ms_drm_queue_alloc(crtc, event_args,
+                           drmmode_SharedPixmapVBlankEventHandler,
+                           drmmode_SharedPixmapVBlankEventAbort);
+
+    vbl.request.type =
+        DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT | drmmode_crtc->vblank_pipe;
+    vbl.request.sequence = 1;
+    vbl.request.signal = (unsigned long) ppriv->flip_seq;
+
+    return drmWaitVBlank(drmmode->fd, &vbl) >= 0;
+}
+
+Bool
+drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
+                         drmmode_ptr drmmode)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    msPixmapPrivPtr ppriv_front = msGetPixmapPriv(drmmode, frontTarget);
+
+    struct vblank_event_args *event_args;
+
+    event_args = calloc(1, sizeof(*event_args));
+    if (!event_args)
+        return FALSE;
+
+    event_args->frontTarget = frontTarget;
+    event_args->backTarget = drmmode_crtc->prime_pixmap;
+    event_args->crtc = crtc;
+    event_args->drmmode = drmmode;
+    event_args->flip = TRUE;
+
+    ppriv_front->flip_seq =
+        ms_drm_queue_alloc(crtc, event_args,
+                           drmmode_SharedPixmapVBlankEventHandler,
+                           drmmode_SharedPixmapVBlankEventAbort);
+
+    if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+                        ppriv_front->fb_id, DRM_MODE_PAGE_FLIP_EVENT,
+                        (void *)(intptr_t) ppriv_front->flip_seq) < 0) {
+        ms_drm_abort_seq(crtc->scrn, ppriv_front->flip_seq);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static Bool
+drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+    if (!drmmode_crtc->enable_flipping)
+        return FALSE;
+
+    if (drmmode_crtc->flipping_active)
+        return TRUE;
+
+    drmmode_crtc->flipping_active =
+        drmmode_SharedPixmapPresent(drmmode_crtc->prime_pixmap_back,
+                                    crtc, drmmode);
+
+    return drmmode_crtc->flipping_active;
+}
+
+static void
+drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
+{
+    uint32_t seq;
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+    if (!drmmode_crtc->flipping_active)
+        return;
+
+    drmmode_crtc->flipping_active = FALSE;
+
+    /* Abort page flip event handler on prime_pixmap */
+    seq = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap)->flip_seq;
+    if (seq)
+        ms_drm_abort_seq(crtc->scrn, seq);
+
+    /* Abort page flip event handler on prime_pixmap_back */
+    seq = msGetPixmapPriv(drmmode,
+                          drmmode_crtc->prime_pixmap_back)->flip_seq;
+    if (seq)
+        ms_drm_abort_seq(crtc->scrn, seq);
+}
+
+static Bool drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
+                                              PixmapPtr *target);
+
+Bool
+drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
+                                   PixmapPtr front, PixmapPtr back)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+    drmmode_crtc->enable_flipping = TRUE;
+
+    /* Set front scanout pixmap */
+    drmmode_crtc->enable_flipping &=
+        drmmode_set_target_scanout_pixmap(crtc, front,
+                                          &drmmode_crtc->prime_pixmap);
+    if (!drmmode_crtc->enable_flipping)
+        return FALSE;
+
+    /* Set back scanout pixmap */
+    drmmode_crtc->enable_flipping &=
+        drmmode_set_target_scanout_pixmap(crtc, back,
+                                          &drmmode_crtc->prime_pixmap_back);
+    if (!drmmode_crtc->enable_flipping) {
+        drmmode_set_target_scanout_pixmap(crtc, NULL,
+                                          &drmmode_crtc->prime_pixmap);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+void
+drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+    drmmode_crtc->enable_flipping = FALSE;
+
+    drmmode_FiniSharedPixmapFlipping(crtc, drmmode);
+
+    drmmode_set_target_scanout_pixmap(crtc, NULL, &drmmode_crtc->prime_pixmap);
+
+    drmmode_set_target_scanout_pixmap(crtc, NULL,
+                                      &drmmode_crtc->prime_pixmap_back);
+}
+
 static void
 drmmode_ConvertFromKMode(ScrnInfoPtr scrn,
                          drmModeModeInfo * kmode, DisplayModePtr mode)
@@ -499,6 +732,9 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
         drmmode_crtc->need_modeset = FALSE;
         crtc->funcs->dpms(crtc, DPMSModeOn);
 
+        if (drmmode_crtc->prime_pixmap_back)
+            drmmode_InitSharedPixmapFlipping(crtc, drmmode);
+
         /* go through all the outputs and force DPMS them back on? */
         for (i = 0; i < xf86_config->num_output; i++) {
             xf86OutputPtr output = xf86_config->output[i];
@@ -629,7 +865,8 @@ drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
 }
 
 static Bool
-drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix)
+drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
+                                      PixmapPtr *target)
 {
     ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
     PixmapPtr screenpix = screen->GetScreenPixmap(screen);
@@ -637,9 +874,10 @@ drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix)
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
     int c, total_width = 0, max_height = 0, this_x = 0;
 
-    if (drmmode_crtc->prime_pixmap) {
-        PixmapStopDirtyTracking(drmmode_crtc->prime_pixmap, screenpix);
+    if (*target) {
+        PixmapStopDirtyTracking(*target, screenpix);
         drmmode_crtc->prime_pixmap_x = 0;
+        *target = NULL;
     }
 
     if (!ppix)
@@ -674,40 +912,43 @@ drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix)
     }
     drmmode_crtc->prime_pixmap_x = this_x;
     PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0);
+    *target = ppix;
     return TRUE;
 }
 
 static Bool
-drmmode_set_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix)
+drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix,
+                                      PixmapPtr *target)
 {
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
     drmmode_ptr drmmode = drmmode_crtc->drmmode;
     msPixmapPrivPtr ppriv;
     void *ptr;
 
-    if (drmmode_crtc->prime_pixmap) {
-        ppriv = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap);
+    if (*target) {
+        ppriv = msGetPixmapPriv(drmmode, *target);
         drmModeRmFB(drmmode->fd, ppriv->fb_id);
-    }
-    if (drmmode_crtc->slave_damage) {
-        DamageUnregister(drmmode_crtc->slave_damage);
-        drmmode_crtc->slave_damage = NULL;
+        if (ppriv->slave_damage) {
+            DamageUnregister(ppriv->slave_damage);
+            ppriv->slave_damage = NULL;
+        }
+        *target = NULL;
     }
 
     if (!ppix)
         return TRUE;
 
     ppriv = msGetPixmapPriv(drmmode, ppix);
-    if (!drmmode_crtc->slave_damage) {
-        drmmode_crtc->slave_damage = DamageCreate(NULL, NULL,
-                                                  DamageReportNone,
-                                                  TRUE,
-                                                  crtc->randr_crtc->pScreen,
-                                                  NULL);
+    if (!ppriv->slave_damage) {
+        ppriv->slave_damage = DamageCreate(NULL, NULL,
+                                           DamageReportNone,
+                                           TRUE,
+                                           crtc->randr_crtc->pScreen,
+                                           NULL);
     }
     ptr = drmmode_map_slave_bo(drmmode, ppriv);
     ppix->devPrivate.ptr = ptr;
-    DamageRegister(&ppix->drawable, drmmode_crtc->slave_damage);
+    DamageRegister(&ppix->drawable, ppriv->slave_damage);
 
     if (ppriv->fb_id == 0) {
         drmModeAddFB(drmmode->fd, ppix->drawable.width,
@@ -716,25 +957,34 @@ drmmode_set_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix)
                      ppix->drawable.bitsPerPixel,
                      ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id);
     }
+    *target = ppix;
     return TRUE;
 }
 
 static Bool
-drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
+drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
+                                  PixmapPtr *target)
 {
-    Bool ret;
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
     drmmode_ptr drmmode = drmmode_crtc->drmmode;
 
     if (drmmode->reverse_prime_offload_mode)
-        ret = drmmode_set_scanout_pixmap_gpu(crtc, ppix);
+        return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target);
     else
-        ret = drmmode_set_scanout_pixmap_cpu(crtc, ppix);
+        return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target);
+}
 
-    if (ret)
-        drmmode_crtc->prime_pixmap = ppix;
+static Bool
+drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
-    return ret;
+    /* Use DisableSharedPixmapFlipping before switching to single buf */
+    if (drmmode_crtc->enable_flipping)
+        return FALSE;
+
+    return drmmode_set_target_scanout_pixmap(crtc, ppix,
+                                             &drmmode_crtc->prime_pixmap);
 }
 
 static void *
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 36c6e91..3161bba 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -99,12 +99,12 @@ typedef struct {
     struct dumb_bo *cursor_bo;
     Bool cursor_up;
     uint16_t lut_r[256], lut_g[256], lut_b[256];
-    DamagePtr slave_damage;
 
     drmmode_bo rotate_bo;
     unsigned rotate_fb_id;
 
     PixmapPtr prime_pixmap;
+    PixmapPtr prime_pixmap_back;
     unsigned prime_pixmap_x;
 
     /**
@@ -120,6 +120,9 @@ typedef struct {
     /** @} */
 
     Bool need_modeset;
+
+    Bool enable_flipping;
+    Bool flipping_active;
 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
 
 typedef struct {
@@ -146,6 +149,12 @@ typedef struct {
 typedef struct _msPixmapPriv {
     uint32_t fb_id;
     struct dumb_bo *backing_bo; /* if this pixmap is backed by a dumb bo */
+
+    DamagePtr slave_damage;
+
+    /** Fields for flipping shared pixmaps */
+    int flip_seq; /* seq of current page flip event handler */
+    Bool wait_for_damage; /* if we have requested damage notification from source */
 } msPixmapPrivRec, *msPixmapPrivPtr;
 
 extern DevPrivateKeyRec msPixmapPrivateKeyRec;
@@ -164,6 +173,14 @@ Bool drmmode_SetSlaveBO(PixmapPtr ppix,
                         drmmode_ptr drmmode,
                         int fd_handle, int pitch, int size);
 
+Bool drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
+                                        PixmapPtr front, PixmapPtr back);
+Bool drmmode_SharedPixmapPresentOnVBlank(PixmapPtr frontTarget, xf86CrtcPtr crtc,
+                                         drmmode_ptr drmmode);
+Bool drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
+                              drmmode_ptr drmmode);
+void drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode);
+
 extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp);
 void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y);
 extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw);
-- 
1.9.1



More information about the xorg-devel mailing list