[PATCH 1/5] present: Introduce internal flip mode API

Roman Gilg subdiff at gmail.com
Tue Aug 29 15:24:28 UTC 2017


The current mode of operation only allows flips per screen.
In order to allow other more advanced modes (such as flips per window),
introduce an internal API for adding and maintaining those modes easily.

A mode "mde" is selected by calling the approriate present_mdemode_init
function on a particular ScreenPtr. Internally then several function
hooks need to be set. When possible common code between modes is in
present.c and diverging functionality shall go in present_mdemode.c.

This patch only adds all the API hooks and rewires the currently only
supported screen flipping as the first available mode in the new API.
There is otherwise no change in functionality and the current workings
are meant to stay completely the same.

The scrmode is also used, when flipping is not supported by the hardware.

Signed-off-by: Roman Gilg <subdiff at gmail.com>
---
 present/Makefile.am       |   3 +-
 present/meson.build       |   1 +
 present/present.c         | 899 +++++++++-------------------------------------
 present/present_priv.h    | 170 ++++++++-
 present/present_screen.c  |  69 ++--
 present/present_scrmode.c | 770 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 1136 insertions(+), 776 deletions(-)
 create mode 100644 present/present_scrmode.c

diff --git a/present/Makefile.am b/present/Makefile.am
index 7fea669..14b2fac 100644
--- a/present/Makefile.am
+++ b/present/Makefile.am
@@ -12,6 +12,7 @@ libpresent_la_SOURCES = \
 	present_notify.c \
 	present_priv.h \
 	present_request.c \
-	present_screen.c
+	present_screen.c \
+	present_scrmode.c
 
 sdk_HEADERS = present.h presentext.h
diff --git a/present/meson.build b/present/meson.build
index a4296ca..4296327 100644
--- a/present/meson.build
+++ b/present/meson.build
@@ -6,6 +6,7 @@ srcs_present = [
     'present_notify.c',
     'present_request.c',
     'present_screen.c',
+    'present_scrmode.c',
 ]
 
 libxserver_present = static_library('libxserver_present',
diff --git a/present/present.c b/present/present.c
index aa9c041..5a2fd93 100644
--- a/present/present.c
+++ b/present/present.c
@@ -32,30 +32,6 @@
 #include <time.h>
 #endif
 
-static uint64_t         present_event_id;
-static struct xorg_list present_exec_queue;
-static struct xorg_list present_flip_queue;
-
-#if 0
-#define DebugPresent(x) ErrorF x
-#else
-#define DebugPresent(x)
-#endif
-
-static void
-present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
-
-/*
- * Returns:
- * TRUE if the first MSC value is after the second one
- * FALSE if the first MSC value is equal to or before the second one
- */
-static Bool
-msc_is_after(uint64_t test, uint64_t reference)
-{
-    return (int64_t)(test - reference) > 0;
-}
-
 /*
  * Returns:
  * TRUE if the first MSC value is equal to or after the second one
@@ -70,7 +46,7 @@ msc_is_equal_or_after(uint64_t test, uint64_t reference)
 /*
  * Copies the update region from a pixmap to the target drawable
  */
-static void
+void
 present_copy_region(DrawablePtr drawable,
                     PixmapPtr pixmap,
                     RegionPtr update,
@@ -103,104 +79,7 @@ present_copy_region(DrawablePtr drawable,
     FreeScratchGC(gc);
 }
 
-static inline PixmapPtr
-present_flip_pending_pixmap(ScreenPtr screen)
-{
-    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-
-    if (!screen_priv)
-        return NULL;
-
-    if (!screen_priv->flip_pending)
-        return NULL;
-
-    return screen_priv->flip_pending->pixmap;
-}
-
-static Bool
-present_check_flip(RRCrtcPtr    crtc,
-                   WindowPtr    window,
-                   PixmapPtr    pixmap,
-                   Bool         sync_flip,
-                   RegionPtr    valid,
-                   int16_t      x_off,
-                   int16_t      y_off)
-{
-    ScreenPtr                   screen = window->drawable.pScreen;
-    PixmapPtr                   window_pixmap;
-    WindowPtr                   root = screen->root;
-    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-
-    if (!screen_priv)
-        return FALSE;
-
-    if (!screen_priv->info)
-        return FALSE;
-
-    if (!crtc)
-        return FALSE;
-
-    /* Check to see if the driver supports flips at all */
-    if (!screen_priv->info->flip)
-        return FALSE;
-
-    /* Make sure the window hasn't been redirected with Composite */
-    window_pixmap = screen->GetWindowPixmap(window);
-    if (window_pixmap != screen->GetScreenPixmap(screen) &&
-        window_pixmap != screen_priv->flip_pixmap &&
-        window_pixmap != present_flip_pending_pixmap(screen))
-        return FALSE;
-
-    /* Check for full-screen window */
-    if (!RegionEqual(&window->clipList, &root->winSize)) {
-        return FALSE;
-    }
-
-    /* Source pixmap must align with window exactly */
-    if (x_off || y_off) {
-        return FALSE;
-    }
-
-    /* Make sure the area marked as valid fills the screen */
-    if (valid && !RegionEqual(valid, &root->winSize)) {
-        return FALSE;
-    }
-
-    /* Does the window match the pixmap exactly? */
-    if (window->drawable.x != 0 || window->drawable.y != 0 ||
-#ifdef COMPOSITE
-        window->drawable.x != pixmap->screen_x || window->drawable.y != pixmap->screen_y ||
-#endif
-        window->drawable.width != pixmap->drawable.width ||
-        window->drawable.height != pixmap->drawable.height) {
-        return FALSE;
-    }
-
-    /* Ask the driver for permission */
-    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;
-        }
-    }
-
-    return TRUE;
-}
-
-static Bool
-present_flip(RRCrtcPtr crtc,
-             uint64_t event_id,
-             uint64_t target_msc,
-             PixmapPtr pixmap,
-             Bool sync_flip)
-{
-    ScreenPtr                   screen = 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);
-}
-
-static void
+void
 present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_t ust, uint64_t crtc_msc)
 {
     int         n;
@@ -216,7 +95,7 @@ present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_
     }
 }
 
-static void
+void
 present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence)
 {
     if (present_fence)
@@ -236,10 +115,7 @@ present_get_crtc(WindowPtr window)
     if (!screen_priv)
         return NULL;
 
-    if (!screen_priv->info)
-        return NULL;
-
-    return (*screen_priv->info->get_crtc)(window);
+    return screen_priv->get_crtc(screen_priv, window);
 }
 
 uint32_t
@@ -255,127 +131,7 @@ present_query_capabilities(RRCrtcPtr crtc)
     if (!screen_priv)
         return 0;
 
-    if (!screen_priv->info)
-        return 0;
-
-    return screen_priv->info->capabilities;
-}
-
-static int
-present_get_ust_msc(ScreenPtr screen, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
-{
-    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-
-    if (crtc == NULL)
-        return present_fake_get_ust_msc(screen, ust, msc);
-    else
-        return (*screen_priv->info->get_ust_msc)(crtc, ust, msc);
-}
-
-static void
-present_flush(WindowPtr window)
-{
-    ScreenPtr                   screen = window->drawable.pScreen;
-    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-
-    if (!screen_priv)
-        return;
-
-    if (!screen_priv->info)
-        return;
-
-    (*screen_priv->info->flush) (window);
-}
-
-static int
-present_queue_vblank(ScreenPtr screen,
-                     RRCrtcPtr crtc,
-                     uint64_t event_id,
-                     uint64_t msc)
-{
-    Bool                        ret;
-
-    if (crtc == NULL)
-        ret = present_fake_queue_vblank(screen, event_id, msc);
-    else
-    {
-        present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-        ret = (*screen_priv->info->queue_vblank) (crtc, event_id, msc);
-    }
-    return ret;
-}
-
-static uint64_t
-present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc)
-{
-    present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
-
-    if (crtc != window_priv->crtc) {
-        uint64_t        old_ust, old_msc;
-
-        if (window_priv->crtc == PresentCrtcNeverSet) {
-            window_priv->msc_offset = 0;
-        } else {
-            /* The old CRTC may have been turned off, in which case
-             * we'll just use whatever previous MSC we'd seen from this CRTC
-             */
-
-            if (present_get_ust_msc(window->drawable.pScreen, window_priv->crtc, &old_ust, &old_msc) != Success)
-                old_msc = window_priv->msc;
-
-            window_priv->msc_offset += new_msc - old_msc;
-        }
-        window_priv->crtc = crtc;
-    }
-
-    return window_msc + window_priv->msc_offset;
-}
-
-/*
- * When the wait fence or previous flip is completed, it's time
- * to re-try the request
- */
-static void
-present_re_execute(present_vblank_ptr vblank)
-{
-    uint64_t            ust = 0, crtc_msc = 0;
-
-    if (vblank->crtc)
-        (void) present_get_ust_msc(vblank->screen, vblank->crtc, &ust, &crtc_msc);
-
-    present_execute(vblank, ust, crtc_msc);
-}
-
-static void
-present_flip_try_ready(ScreenPtr screen)
-{
-    present_vblank_ptr  vblank;
-
-    xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
-        if (vblank->queued) {
-            present_re_execute(vblank);
-            return;
-        }
-    }
-}
-
-static void
-present_flip_idle(ScreenPtr screen)
-{
-    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
-
-    if (screen_priv->flip_pixmap) {
-        present_pixmap_idle(screen_priv->flip_pixmap, screen_priv->flip_window,
-                            screen_priv->flip_serial, screen_priv->flip_idle_fence);
-        if (screen_priv->flip_idle_fence)
-            present_fence_destroy(screen_priv->flip_idle_fence);
-        dixDestroyPixmap(screen_priv->flip_pixmap, screen_priv->flip_pixmap->drawable.id);
-        screen_priv->flip_crtc = NULL;
-        screen_priv->flip_window = NULL;
-        screen_priv->flip_serial = 0;
-        screen_priv->flip_pixmap = NULL;
-        screen_priv->flip_idle_fence = NULL;
-    }
+    return screen_priv->query_capabilities(screen_priv);
 }
 
 struct pixmap_visit {
@@ -395,7 +151,7 @@ present_set_tree_pixmap_visit(WindowPtr window, void *data)
     return WT_WALKCHILDREN;
 }
 
-static void
+void
 present_set_tree_pixmap(WindowPtr window,
                         PixmapPtr expected,
                         PixmapPtr pixmap)
@@ -413,347 +169,81 @@ present_set_tree_pixmap(WindowPtr window,
     TraverseTree(window, present_set_tree_pixmap_visit, &visit);
 }
 
-void
-present_restore_screen_pixmap(ScreenPtr screen)
-{
-    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
-    PixmapPtr screen_pixmap = (*screen->GetScreenPixmap)(screen);
-    PixmapPtr flip_pixmap;
-    WindowPtr flip_window;
-
-    if (screen_priv->flip_pending) {
-        flip_window = screen_priv->flip_pending->window;
-        flip_pixmap = screen_priv->flip_pending->pixmap;
-    } else {
-        flip_window = screen_priv->flip_window;
-        flip_pixmap = screen_priv->flip_pixmap;
-    }
-
-    assert (flip_pixmap);
-
-    /* Update the screen pixmap with the current flip pixmap contents
-     * Only do this the first time for a particular unflip operation, or
-     * we'll probably scribble over other windows
-     */
-    if (screen->root && screen->GetWindowPixmap(screen->root) == flip_pixmap)
-        present_copy_region(&screen_pixmap->drawable, flip_pixmap, NULL, 0, 0);
-
-    /* Switch back to using the screen pixmap now to avoid
-     * 2D applications drawing to the wrong pixmap.
-     */
-    if (flip_window)
-        present_set_tree_pixmap(flip_window, flip_pixmap, screen_pixmap);
-    if (screen->root)
-        present_set_tree_pixmap(screen->root, NULL, screen_pixmap);
-}
-
-void
-present_set_abort_flip(ScreenPtr screen)
-{
-    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
-
-    if (!screen_priv->flip_pending->abort_flip) {
-        present_restore_screen_pixmap(screen);
-        screen_priv->flip_pending->abort_flip = TRUE;
-    }
-}
-
-static void
-present_unflip(ScreenPtr screen)
-{
-    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
-
-    assert (!screen_priv->unflip_event_id);
-    assert (!screen_priv->flip_pending);
-
-    present_restore_screen_pixmap(screen);
-
-    screen_priv->unflip_event_id = ++present_event_id;
-    DebugPresent(("u %lld\n", screen_priv->unflip_event_id));
-    (*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id);
-}
-
-static void
-present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
-{
-    ScreenPtr                   screen = vblank->screen;
-    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-
-    DebugPresent(("\tn %lld %p %8lld: %08lx -> %08lx\n",
-                  vblank->event_id, vblank, vblank->target_msc,
-                  vblank->pixmap ? vblank->pixmap->drawable.id : 0,
-                  vblank->window ? vblank->window->drawable.id : 0));
-
-    assert (vblank == screen_priv->flip_pending);
-
-    present_flip_idle(screen);
-
-    xorg_list_del(&vblank->event_queue);
-
-    /* Transfer reference for pixmap and fence from vblank to screen_priv */
-    screen_priv->flip_crtc = vblank->crtc;
-    screen_priv->flip_window = vblank->window;
-    screen_priv->flip_serial = vblank->serial;
-    screen_priv->flip_pixmap = vblank->pixmap;
-    screen_priv->flip_sync = vblank->sync_flip;
-    screen_priv->flip_idle_fence = vblank->idle_fence;
-
-    vblank->pixmap = NULL;
-    vblank->idle_fence = NULL;
-
-    screen_priv->flip_pending = NULL;
-
-    if (vblank->abort_flip)
-        present_unflip(screen);
-
-    present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
-    present_vblank_destroy(vblank);
-
-    present_flip_try_ready(screen);
-}
-
-void
-present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc)
-{
-    present_vblank_ptr  vblank;
-    int                 s;
-
-    if (!event_id)
-        return;
-    DebugPresent(("\te %lld ust %lld msc %lld\n", event_id, ust, msc));
-    xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) {
-        int64_t match = event_id - vblank->event_id;
-        if (match == 0) {
-            present_execute(vblank, ust, msc);
-            return;
-        }
-        if (match < 0)
-            break;
-    }
-    xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
-        if (vblank->event_id == event_id) {
-            if (vblank->queued)
-                present_execute(vblank, ust, msc);
-            else
-                present_flip_notify(vblank, ust, msc);
-            return;
-        }
-    }
-
-    for (s = 0; s < screenInfo.numScreens; s++) {
-        ScreenPtr               screen = screenInfo.screens[s];
-        present_screen_priv_ptr screen_priv = present_screen_priv(screen);
-
-        if (event_id == screen_priv->unflip_event_id) {
-            DebugPresent(("\tun %lld\n", event_id));
-            screen_priv->unflip_event_id = 0;
-            present_flip_idle(screen);
-            present_flip_try_ready(screen);
-            return;
-        }
-    }
-}
-
-/*
- * 'window' is being reconfigured. Check to see if it is involved
- * in flipping and clean up as necessary
- */
-void
-present_check_flip_window (WindowPtr window)
-{
-    ScreenPtr                   screen = window->drawable.pScreen;
-    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-    present_window_priv_ptr     window_priv = present_window_priv(window);
-    present_vblank_ptr          flip_pending = screen_priv->flip_pending;
-    present_vblank_ptr          vblank;
-
-    /* If this window hasn't ever been used with Present, it can't be
-     * flipping
-     */
-    if (!window_priv)
-        return;
-
-    if (screen_priv->unflip_event_id)
-        return;
-
-    if (flip_pending) {
-        /*
-         * Check pending flip
-         */
-        if (flip_pending->window == window) {
-            if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
-                                    flip_pending->sync_flip, NULL, 0, 0))
-                present_set_abort_flip(screen);
-        }
-    } else {
-        /*
-         * 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))
-                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)) {
-            vblank->flip = FALSE;
-            if (vblank->sync_flip)
-                vblank->requeue = TRUE;
-        }
-    }
-}
-
 /*
  * Called when the wait fence is triggered; just gets the current msc/ust and
- * calls present_execute again. That will re-check the fence and pend the
+ * calls the proper execute again. That will re-check the fence and pend the
  * request again if it's still not actually ready
  */
 static void
 present_wait_fence_triggered(void *param)
 {
-    present_vblank_ptr  vblank = param;
-    present_re_execute(vblank);
-}
+    present_vblank_ptr      vblank = param;
+    ScreenPtr               screen = vblank->screen;
+    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
 
-/*
- * Once the required MSC has been reached, execute the pending request.
- *
- * For requests to actually present something, either blt contents to
- * the screen or queue a frame buffer swap.
- *
- * For requests to just get the current MSC/UST combo, skip that part and
- * go straight to event delivery
- */
+    screen_priv->re_execute(vblank);
+}
 
-static void
-present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
+Bool
+present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc)
 {
     WindowPtr                   window = vblank->window;
     ScreenPtr                   screen = window->drawable.pScreen;
-    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-    uint8_t                     mode;
+    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
 
     if (vblank->requeue) {
         vblank->requeue = FALSE;
         if (msc_is_after(vblank->target_msc, crtc_msc) &&
-            Success == present_queue_vblank(screen,
-                                            vblank->crtc,
-                                            vblank->event_id,
-                                            vblank->target_msc))
-            return;
+            Success == screen_priv->queue_vblank(screen,
+                                                 vblank->window,
+                                                 vblank->crtc,
+                                                 vblank->event_id,
+                                                 vblank->target_msc))
+            return TRUE;
     }
 
     if (vblank->wait_fence) {
         if (!present_fence_check_triggered(vblank->wait_fence)) {
             present_fence_set_callback(vblank->wait_fence, present_wait_fence_triggered, vblank);
-            return;
-        }
-    }
-
-    if (vblank->flip && vblank->pixmap && vblank->window) {
-        if (screen_priv->flip_pending || screen_priv->unflip_event_id) {
-            DebugPresent(("\tr %lld %p (pending %p unflip %lld)\n",
-                          vblank->event_id, vblank,
-                          screen_priv->flip_pending, screen_priv->unflip_event_id));
-            xorg_list_del(&vblank->event_queue);
-            xorg_list_append(&vblank->event_queue, &present_flip_queue);
-            vblank->flip_ready = TRUE;
-            return;
+            return TRUE;
         }
     }
+    return FALSE;
+}
 
-    xorg_list_del(&vblank->event_queue);
-    xorg_list_del(&vblank->window_list);
-    vblank->queued = FALSE;
-
-    if (vblank->pixmap && vblank->window) {
-
-        if (vblank->flip) {
-
-            DebugPresent(("\tf %lld %p %8lld: %08lx -> %08lx\n",
-                          vblank->event_id, vblank, crtc_msc,
-                          vblank->pixmap->drawable.id, vblank->window->drawable.id));
-
-            /* Prepare to flip by placing it in the flip queue and
-             * and sticking it into the flip_pending field
-             */
-            screen_priv->flip_pending = vblank;
-
-            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)) {
-                RegionPtr damage;
-
-                /* Fix window pixmaps:
-                 *  1) Restore previous flip window pixmap
-                 *  2) Set current flip window pixmap to the new pixmap
-                 */
-                if (screen_priv->flip_window && screen_priv->flip_window != window)
-                    present_set_tree_pixmap(screen_priv->flip_window,
-                                            screen_priv->flip_pixmap,
-                                            (*screen->GetScreenPixmap)(screen));
-                present_set_tree_pixmap(vblank->window, NULL, vblank->pixmap);
-                present_set_tree_pixmap(screen->root, NULL, vblank->pixmap);
-
-                /* Report update region as damaged
-                 */
-                if (vblank->update) {
-                    damage = vblank->update;
-                    RegionIntersect(damage, damage, &window->clipList);
-                } else
-                    damage = &window->clipList;
-
-                DamageDamageRegion(&vblank->window->drawable, damage);
-                return;
-            }
+void
+present_execute_copy(present_vblank_ptr vblank, uint64_t crtc_msc)
+{
+    WindowPtr                   window = vblank->window;
+    ScreenPtr                   screen = window->drawable.pScreen;
+    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
 
-            xorg_list_del(&vblank->event_queue);
-            /* Oops, flip failed. Clear the flip_pending field
-              */
-            screen_priv->flip_pending = NULL;
-            vblank->flip = FALSE;
-        }
-        DebugPresent(("\tc %p %8lld: %08lx -> %08lx\n", vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
-        if (screen_priv->flip_pending) {
-
-            /* Check pending flip
-             */
-            if (window == screen_priv->flip_pending->window)
-                present_set_abort_flip(screen);
-        } else if (!screen_priv->unflip_event_id) {
-
-            /* Check current flip
-             */
-            if (window == screen_priv->flip_window)
-                present_unflip(screen);
-        }
+    /* If present_flip failed, we may have to requeue for the target MSC */
+    if (vblank->target_msc == crtc_msc + 1 &&
+        Success == screen_priv->queue_vblank(screen,
+                                             vblank->window,
+                                             vblank->crtc,
+                                             vblank->event_id,
+                                             vblank->target_msc)) {
+        vblank->queued = TRUE;
+        return;
+    }
 
-        /* If present_flip failed, we may have to requeue for the target MSC */
-        if (vblank->target_msc == crtc_msc + 1 &&
-            Success == present_queue_vblank(screen,
-                                            vblank->crtc,
-                                            vblank->event_id,
-                                            vblank->target_msc)) {
-            xorg_list_add(&vblank->event_queue, &present_exec_queue);
-            xorg_list_append(&vblank->window_list,
-                             &present_get_window_priv(window, TRUE)->vblank);
-            vblank->queued = TRUE;
-            return;
-        }
+    present_copy_region(&window->drawable, vblank->pixmap, vblank->update, vblank->x_off, vblank->y_off);
 
-        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,
+     * which is then freed, freeing the region
+     */
+    vblank->update = NULL;
+    screen_priv->flush(window);
 
-        /* present_copy_region sticks the region into a scratch GC,
-         * which is then freed, freeing the region
-         */
-        vblank->update = NULL;
-        present_flush(window);
+    present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
+}
 
-        present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
-    }
+void
+present_execute_post(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
+{
+    uint8_t mode;
 
     /* Compute correct CompleteMode
      */
@@ -766,11 +256,37 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
     else
         mode = PresentCompleteModeCopy;
 
-
     present_vblank_notify(vblank, vblank->kind, mode, ust, crtc_msc);
     present_vblank_destroy(vblank);
 }
 
+void
+present_adjust_timings(uint32_t options,
+                uint64_t *crtc_msc,
+                uint64_t *target_msc,
+                uint64_t divisor,
+                uint64_t remainder)
+{
+    /* Adjust target_msc to match modulus
+     */
+    if (msc_is_equal_or_after(*crtc_msc, *target_msc)) {
+        if (divisor != 0) {
+            *target_msc = *crtc_msc - (*crtc_msc % divisor) + remainder;
+            if (options & PresentOptionAsync) {
+                if (msc_is_after(*crtc_msc, *target_msc))
+                    *target_msc += divisor;
+            } else {
+                if (msc_is_equal_or_after(*crtc_msc, *target_msc))
+                    *target_msc += divisor;
+            }
+        } else {
+            *target_msc = *crtc_msc;
+            if (!(options & PresentOptionAsync))
+                (*target_msc)++;
+        }
+    }
+}
+
 int
 present_pixmap(WindowPtr window,
                PixmapPtr pixmap,
@@ -789,11 +305,6 @@ present_pixmap(WindowPtr window,
                present_notify_ptr notifies,
                int num_notifies)
 {
-    uint64_t                    ust = 0;
-    uint64_t                    target_msc;
-    uint64_t                    crtc_msc = 0;
-    int                         ret;
-    present_vblank_ptr          vblank, tmp;
     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);
@@ -801,93 +312,78 @@ present_pixmap(WindowPtr window,
     if (!window_priv)
         return BadAlloc;
 
-    if (!screen_priv || !screen_priv->info)
-        target_crtc = NULL;
-    else if (!target_crtc) {
-        /* Update the CRTC if we have a pixmap or we don't have a CRTC
-         */
-        if (!pixmap)
-            target_crtc = window_priv->crtc;
-
-        if (!target_crtc || target_crtc == PresentCrtcNeverSet)
-            target_crtc = present_get_crtc(window);
-    }
-
-    ret = present_get_ust_msc(screen, target_crtc, &ust, &crtc_msc);
-
-    target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
-
-    if (ret == Success) {
-        /* Stash the current MSC away in case we need it later
-         */
-        window_priv->msc = crtc_msc;
-    }
-
-    /* Adjust target_msc to match modulus
-     */
-    if (msc_is_equal_or_after(crtc_msc, target_msc)) {
-        if (divisor != 0) {
-            target_msc = crtc_msc - (crtc_msc % divisor) + remainder;
-            if (options & PresentOptionAsync) {
-                if (msc_is_after(crtc_msc, target_msc))
-                    target_msc += divisor;
-            } else {
-                if (msc_is_equal_or_after(crtc_msc, target_msc))
-                    target_msc += divisor;
-            }
-        } else {
-            target_msc = crtc_msc;
-            if (!(options & PresentOptionAsync))
-                target_msc++;
-        }
-    }
-
-    /*
-     * Look for a matching presentation already on the list and
-     * don't bother doing the previous one if this one will overwrite it
-     * in the same frame
-     */
-
-    if (!update && pixmap) {
-        xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
-
-            if (!vblank->pixmap)
-                continue;
-
-            if (!vblank->queued)
-                continue;
-
-            if (vblank->crtc != target_crtc || vblank->target_msc != target_msc)
-                continue;
-
-            DebugPresent(("\tx %lld %p %8lld: %08lx -> %08lx (crtc %p)\n",
-                          vblank->event_id, vblank, vblank->target_msc,
-                          vblank->pixmap->drawable.id, vblank->window->drawable.id,
-                          vblank->crtc));
+    return screen_priv->present_pixmap(window_priv,
+                                       pixmap,
+                                       serial,
+                                       valid,
+                                       update,
+                                       x_off,
+                                       y_off,
+                                       target_crtc,
+                                       wait_fence,
+                                       idle_fence,
+                                       options,
+                                       window_msc,
+                                       divisor,
+                                       remainder,
+                                       notifies,
+                                       num_notifies);
+}
 
-            present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
-            present_fence_destroy(vblank->idle_fence);
-            dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
+int
+present_notify_msc(WindowPtr window,
+                   CARD32 serial,
+                   uint64_t target_msc,
+                   uint64_t divisor,
+                   uint64_t remainder)
+{
+    return present_pixmap(window,
+                          NULL,
+                          serial,
+                          NULL, NULL,
+                          0, 0,
+                          NULL,
+                          NULL, NULL,
+                          divisor == 0 ? PresentOptionAsync : 0,
+                          target_msc, divisor, remainder, NULL, 0);
+}
 
-            vblank->pixmap = NULL;
-            vblank->idle_fence = NULL;
-            vblank->flip = FALSE;
-            if (vblank->flip_ready)
-                present_re_execute(vblank);
-        }
-    }
+present_vblank_ptr
+present_vblank_create(present_window_priv_ptr window_priv,
+                      PixmapPtr pixmap,
+                      CARD32 serial,
+                      RegionPtr valid,
+                      RegionPtr update,
+                      int16_t x_off,
+                      int16_t y_off,
+                      RRCrtcPtr target_crtc,
+                      SyncFence *wait_fence,
+                      SyncFence *idle_fence,
+                      uint32_t options,
+                      const uint32_t *capabilities,
+                      present_notify_ptr notifies,
+                      int num_notifies,
+                      uint64_t *target_msc,
+                      uint64_t crtc_msc)
+{
+    WindowPtr                   window = window_priv->window;
+    ScreenPtr                   screen = window->drawable.pScreen;
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+    present_vblank_ptr          vblank;
 
     vblank = calloc (1, sizeof (present_vblank_rec));
     if (!vblank)
-        return BadAlloc;
+        return NULL;
 
-    xorg_list_append(&vblank->window_list, &window_priv->vblank);
+    xorg_list_append(&vblank->window_list, &window_priv->vblank_queue);
     xorg_list_init(&vblank->event_queue);
 
     vblank->screen = screen;
     vblank->window = window;
     vblank->pixmap = pixmap;
-    vblank->event_id = ++present_event_id;
+
+    screen_priv->create_event_id(window_priv, vblank);
+
     if (pixmap) {
         vblank->kind = PresentCompleteKindPixmap;
         pixmap->refcnt++;
@@ -909,7 +405,7 @@ present_pixmap(WindowPtr window,
 
     vblank->x_off = x_off;
     vblank->y_off = y_off;
-    vblank->target_msc = target_msc;
+    vblank->target_msc = *target_msc;
     vblank->crtc = target_crtc;
     vblank->msc_offset = window_priv->msc_offset;
     vblank->notifies = notifies;
@@ -917,15 +413,15 @@ present_pixmap(WindowPtr window,
 
     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))
+        capabilities) {
+        if (msc_is_after(*target_msc, crtc_msc) &&
+            screen_priv->check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off))
         {
             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))
+            *target_msc = *target_msc - 1;
+        } else if ((*capabilities & PresentCapabilityAsync) &&
+            screen_priv->check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off))
         {
             vblank->flip = TRUE;
         }
@@ -945,93 +441,33 @@ present_pixmap(WindowPtr window,
 
     if (pixmap)
         DebugPresent(("q %lld %p %8lld: %08lx -> %08lx (crtc %p) flip %d vsync %d serial %d\n",
-                      vblank->event_id, vblank, target_msc,
+                      vblank->event_id, vblank, *target_msc,
                       vblank->pixmap->drawable.id, vblank->window->drawable.id,
                       target_crtc, vblank->flip, vblank->sync_flip, vblank->serial));
 
-    xorg_list_append(&vblank->event_queue, &present_exec_queue);
-    vblank->queued = TRUE;
-    if (msc_is_after(target_msc, crtc_msc)) {
-        ret = present_queue_vblank(screen, target_crtc, vblank->event_id, target_msc);
-        if (ret == Success)
-            return Success;
-
-        DebugPresent(("present_queue_vblank failed\n"));
-    }
-
-    present_execute(vblank, ust, crtc_msc);
-
-    return Success;
+    return vblank;
 
 no_mem:
-    ret = BadAlloc;
     vblank->notifies = NULL;
     present_vblank_destroy(vblank);
-    return ret;
+    return NULL;
 }
 
 void
-present_abort_vblank(ScreenPtr screen, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
-{
-    present_vblank_ptr  vblank;
-
-    if (crtc == NULL)
-        present_fake_abort_vblank(screen, event_id, msc);
-    else
-    {
-        present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
-
-        (*screen_priv->info->abort_vblank) (crtc, event_id, msc);
-    }
-
-    xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) {
-        int64_t match = event_id - vblank->event_id;
-        if (match == 0) {
-            xorg_list_del(&vblank->event_queue);
-            vblank->queued = FALSE;
-            return;
-        }
-        if (match < 0)
-            break;
-    }
-    xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
-        if (vblank->event_id == event_id) {
-            xorg_list_del(&vblank->event_queue);
-            vblank->queued = FALSE;
-            return;
-        }
-    }
-}
-
-int
-present_notify_msc(WindowPtr window,
-                   CARD32 serial,
-                   uint64_t target_msc,
-                   uint64_t divisor,
-                   uint64_t remainder)
+present_vblank_scrap(present_vblank_ptr vblank)
 {
-    return present_pixmap(window,
-                          NULL,
-                          serial,
-                          NULL, NULL,
-                          0, 0,
-                          NULL,
-                          NULL, NULL,
-                          divisor == 0 ? PresentOptionAsync : 0,
-                          target_msc, divisor, remainder, NULL, 0);
-}
-
-void
-present_flip_destroy(ScreenPtr screen)
-{
-    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+    DebugPresent(("\tx %lld %p %8lld: %08lx -> %08lx (crtc %p)\n",
+                  vblank->event_id, vblank, vblank->target_msc,
+                  vblank->pixmap->drawable.id, vblank->window->drawable.id,
+                  vblank->crtc));
 
-    /* Reset window pixmaps back to the screen pixmap */
-    if (screen_priv->flip_pending)
-        present_set_abort_flip(screen);
+    present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
+    present_fence_destroy(vblank->idle_fence);
+    dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
 
-    /* Drop reference to any pending flip or unflip pixmaps. */
-    present_flip_idle(screen);
+    vblank->pixmap = NULL;
+    vblank->idle_fence = NULL;
+    vblank->flip = FALSE;
 }
 
 void
@@ -1040,13 +476,15 @@ present_vblank_destroy(present_vblank_ptr vblank)
     /* Remove vblank from window and screen lists */
     xorg_list_del(&vblank->window_list);
 
+    xorg_list_del(&vblank->event_queue);
+
     DebugPresent(("\td %lld %p %8lld: %08lx -> %08lx\n",
                   vblank->event_id, vblank, vblank->target_msc,
                   vblank->pixmap ? vblank->pixmap->drawable.id : 0,
                   vblank->window ? vblank->window->drawable.id : 0));
 
     /* Drop pixmap reference */
-    if (vblank->pixmap)
+    if (vblank->pixmap && vblank->pixmap->refcnt > 1)
         dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
 
     /* Free regions */
@@ -1066,12 +504,3 @@ present_vblank_destroy(present_vblank_ptr vblank)
 
     free(vblank);
 }
-
-Bool
-present_init(void)
-{
-    xorg_list_init(&present_exec_queue);
-    xorg_list_init(&present_flip_queue);
-    present_fake_queue_init();
-    return TRUE;
-}
diff --git a/present/present_priv.h b/present/present_priv.h
index dfb4bde..80a5b4d 100644
--- a/present/present_priv.h
+++ b/present/present_priv.h
@@ -35,6 +35,12 @@
 #include <xfixes.h>
 #include <randrstr.h>
 
+#if 0
+#define DebugPresent(x) ErrorF x
+#else
+#define DebugPresent(x)
+#endif
+
 extern int present_request;
 
 extern DevPrivateKeyRec present_screen_private_key;
@@ -77,7 +83,58 @@ struct present_vblank {
     Bool                abort_flip;     /* aborting this flip */
 };
 
-typedef struct present_screen_priv {
+typedef struct present_screen_priv present_screen_priv_rec, *present_screen_priv_ptr;
+typedef struct present_window_priv present_window_priv_rec, *present_window_priv_ptr;
+/*
+ * Mode hooks
+ */
+typedef uint32_t (*present_priv_query_capabilities_ptr)(present_screen_priv_ptr screen_priv);
+typedef RRCrtcPtr (*present_priv_get_crtc_ptr)(present_screen_priv_ptr screen_priv,
+                                               WindowPtr window);
+
+typedef Bool (*present_priv_check_flip_ptr)(RRCrtcPtr crtc,
+                                            WindowPtr window,
+                                            PixmapPtr pixmap,
+                                            Bool sync_flip,
+                                            RegionPtr valid,
+                                            int16_t x_off,
+                                            int16_t y_off);
+typedef void (*present_priv_check_flip_window_ptr)(WindowPtr window);
+
+typedef int (*present_priv_pixmap_ptr)(present_window_priv_ptr window,
+                                       PixmapPtr pixmap,
+                                       CARD32 serial,
+                                       RegionPtr valid,
+                                       RegionPtr update,
+                                       int16_t x_off,
+                                       int16_t y_off,
+                                       RRCrtcPtr target_crtc,
+                                       SyncFence *wait_fence,
+                                       SyncFence *idle_fence,
+                                       uint32_t options,
+                                       uint64_t window_msc,
+                                       uint64_t divisor,
+                                       uint64_t remainder,
+                                       present_notify_ptr notifies,
+                                       int num_notifies);
+typedef void (*present_priv_create_event_id_ptr)(present_window_priv_ptr window_priv,
+                                                 present_vblank_ptr vblank);
+typedef int (*present_priv_queue_vblank_ptr)(ScreenPtr screen,
+                                             WindowPtr window,
+                                             RRCrtcPtr crtc,
+                                             uint64_t event_id,
+                                             uint64_t msc);
+typedef void (*present_priv_flush_ptr)(WindowPtr window);
+typedef void (*present_priv_re_execute_ptr)(present_vblank_ptr vblank);
+
+typedef void (*present_priv_abort_vblank_ptr)(ScreenPtr screen,
+                                              WindowPtr window,
+                                              RRCrtcPtr crtc,
+                                              uint64_t event_id,
+                                              uint64_t msc);
+typedef void (*present_priv_flips_destroy_ptr)(ScreenPtr screen);
+
+struct present_screen_priv {
     CloseScreenProcPtr          CloseScreen;
     ConfigNotifyProcPtr         ConfigNotify;
     DestroyWindowProcPtr        DestroyWindow;
@@ -97,7 +154,23 @@ typedef struct present_screen_priv {
     Bool                        flip_sync;
 
     present_screen_info_ptr     info;
-} present_screen_priv_rec, *present_screen_priv_ptr;
+
+    /* Mode hooks */
+    present_priv_query_capabilities_ptr query_capabilities;
+    present_priv_get_crtc_ptr           get_crtc;
+
+    present_priv_check_flip_ptr         check_flip;
+    present_priv_check_flip_window_ptr  check_flip_window;
+
+    present_priv_pixmap_ptr             present_pixmap;
+    present_priv_create_event_id_ptr    create_event_id;
+    present_priv_queue_vblank_ptr       queue_vblank;
+    present_priv_flush_ptr              flush;
+    present_priv_re_execute_ptr         re_execute;
+
+    present_priv_abort_vblank_ptr       abort_vblank;
+    present_priv_flips_destroy_ptr      flips_destroy;
+};
 
 #define wrap(priv,real,mem,func) {\
     priv->mem = real->mem; \
@@ -127,14 +200,15 @@ typedef struct present_event {
     int mask;
 } present_event_rec;
 
-typedef struct present_window_priv {
+struct present_window_priv {
+    WindowPtr              window;
     present_event_ptr      events;
     RRCrtcPtr              crtc;        /* Last reported CRTC from get_ust_msc */
     uint64_t               msc_offset;
     uint64_t               msc;         /* Last reported MSC from the current crtc */
-    struct xorg_list       vblank;
+    struct xorg_list       vblank_queue;
     struct xorg_list       notifies;
-} present_window_priv_rec, *present_window_priv_ptr;
+};
 
 #define PresentCrtcNeverSet     ((RRCrtcPtr) 1)
 
@@ -149,6 +223,13 @@ present_window_priv(WindowPtr window)
 present_window_priv_ptr
 present_get_window_priv(WindowPtr window, Bool create);
 
+/* Returns TRUE if 'test' is after 'reference', FALSE otherwise */
+static inline Bool
+msc_is_after(uint64_t test, uint64_t reference)
+{
+    return (int64_t)(test - reference) > 0;
+}
+
 /*
  * present.c
  */
@@ -178,21 +259,9 @@ present_notify_msc(WindowPtr window,
                    uint64_t remainder);
 
 void
-present_abort_vblank(ScreenPtr screen, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc);
-
-void
 present_vblank_destroy(present_vblank_ptr vblank);
 
 void
-present_flip_destroy(ScreenPtr screen);
-
-void
-present_restore_screen_pixmap(ScreenPtr screen);
-
-void
-present_set_abort_flip(ScreenPtr screen);
-
-void
 present_check_flip_window(WindowPtr window);
 
 RRCrtcPtr
@@ -204,6 +273,73 @@ present_query_capabilities(RRCrtcPtr crtc);
 Bool
 present_init(void);
 
+present_vblank_ptr
+present_vblank_create(present_window_priv_ptr window_priv,
+                      PixmapPtr pixmap,
+                      CARD32 serial,
+                      RegionPtr valid,
+                      RegionPtr update,
+                      int16_t x_off,
+                      int16_t y_off,
+                      RRCrtcPtr target_crtc,
+                      SyncFence *wait_fence,
+                      SyncFence *idle_fence,
+                      uint32_t options,
+                      const uint32_t *capabilities,
+                      present_notify_ptr notifies,
+                      int num_notifies,
+                      uint64_t *target_msc,
+                      uint64_t crtc_msc);
+
+void
+present_vblank_scrap(present_vblank_ptr vblank);
+
+void
+present_adjust_timings(uint32_t options,
+                       uint64_t *crtc_msc,
+                       uint64_t *target_msc,
+                       uint64_t divisor,
+                       uint64_t remainder);
+
+void
+present_execute_post(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
+
+void
+present_execute_copy(present_vblank_ptr vblank, uint64_t crtc_msc);
+
+void
+present_set_tree_pixmap(WindowPtr window,
+                        PixmapPtr expected,
+                        PixmapPtr pixmap);
+
+Bool
+present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc);
+
+void
+present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence);
+
+void
+present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_t ust, uint64_t crtc_msc);
+
+void
+present_copy_region(DrawablePtr drawable,
+                    PixmapPtr pixmap,
+                    RegionPtr update,
+                    int16_t x_off,
+                    int16_t y_off);
+
+/*
+ * present_scrmode.c
+ */
+void
+present_scrmode_set_abort_flip(ScreenPtr screen);
+
+void
+present_scrmode_restore_screen_pixmap(ScreenPtr screen);
+
+void
+present_scrmode_init_scrmode(present_screen_priv_ptr screen_priv);
+
 /*
  * present_event.c
  */
diff --git a/present/present_screen.c b/present/present_screen.c
index 9d03c8a..8072488 100644
--- a/present/present_screen.c
+++ b/present/present_screen.c
@@ -43,8 +43,10 @@ present_get_window_priv(WindowPtr window, Bool create)
     window_priv = calloc (1, sizeof (present_window_priv_rec));
     if (!window_priv)
         return NULL;
-    xorg_list_init(&window_priv->vblank);
+    xorg_list_init(&window_priv->vblank_queue);
     xorg_list_init(&window_priv->notifies);
+
+    window_priv->window = window;
     window_priv->crtc = PresentCrtcNeverSet;
     dixSetPrivate(&window->devPrivates, &present_window_private_key, window_priv);
     return window_priv;
@@ -58,7 +60,7 @@ present_close_screen(ScreenPtr screen)
 {
     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
 
-    present_flip_destroy(screen);
+    screen_priv->flips_destroy(screen);
 
     unwrap(screen_priv, screen, CloseScreen);
     (*screen->CloseScreen) (screen);
@@ -72,18 +74,17 @@ present_close_screen(ScreenPtr screen)
 static void
 present_free_window_vblank(WindowPtr window)
 {
+    ScreenPtr                   screen = window->drawable.pScreen;
     present_window_priv_ptr     window_priv = present_window_priv(window);
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
     present_vblank_ptr          vblank, tmp;
 
-    xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
-        present_abort_vblank(window->drawable.pScreen, vblank->crtc, vblank->event_id, vblank->target_msc);
+    xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank_queue, window_list) {
+        screen_priv->abort_vblank(screen, window, vblank->crtc, vblank->event_id, vblank->target_msc);
         present_vblank_destroy(vblank);
     }
 }
 
-/*
- * Clean up any pending or current flips for this window
- */
 static void
 present_clear_window_flip(WindowPtr window)
 {
@@ -92,11 +93,11 @@ present_clear_window_flip(WindowPtr window)
     present_vblank_ptr          flip_pending = screen_priv->flip_pending;
 
     if (flip_pending && flip_pending->window == window) {
-        present_set_abort_flip(screen);
+        present_scrmode_set_abort_flip(screen);
         flip_pending->window = NULL;
     }
     if (screen_priv->flip_window == window) {
-        present_restore_screen_pixmap(screen);
+        present_scrmode_restore_screen_pixmap(screen);
         screen_priv->flip_window = NULL;
     }
 }
@@ -161,18 +162,15 @@ present_clip_notify(WindowPtr window, int dx, int dy)
     ScreenPtr screen = window->drawable.pScreen;
     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
 
-    present_check_flip_window(window);
+    screen_priv->check_flip_window(window);
     unwrap(screen_priv, screen, ClipNotify)
     if (screen->ClipNotify)
         screen->ClipNotify (window, dx, dy);
     wrap(screen_priv, screen, ClipNotify, present_clip_notify);
 }
 
-/*
- * Initialize a screen for use with present
- */
-int
-present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
+static Bool
+present_screen_register_priv_keys(void)
 {
     if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
         return FALSE;
@@ -180,19 +178,44 @@ present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
     if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
         return FALSE;
 
+    return TRUE;
+}
+
+static present_screen_priv_ptr
+present_screen_priv_init(ScreenPtr screen)
+{
+    present_screen_priv_ptr screen_priv;
+
+    screen_priv = calloc(1, sizeof (present_screen_priv_rec));
+    if (!screen_priv)
+        return NULL;
+
+    wrap(screen_priv, screen, CloseScreen, present_close_screen);
+    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
+    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
+    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
+
+    dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
+
+    return screen_priv;
+}
+
+/*
+ * Initialize a screen for use with present in default screen mode
+ */
+int
+present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
+{
+    if (!present_screen_register_priv_keys())
+        return FALSE;
+
     if (!present_screen_priv(screen)) {
-        present_screen_priv_ptr screen_priv = calloc(1, sizeof (present_screen_priv_rec));
+        present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
         if (!screen_priv)
             return FALSE;
 
-        wrap(screen_priv, screen, CloseScreen, present_close_screen);
-        wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
-        wrap(screen_priv, screen, ConfigNotify, present_config_notify);
-        wrap(screen_priv, screen, ClipNotify, present_clip_notify);
-
         screen_priv->info = info;
-
-        dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
+        present_scrmode_init_scrmode(screen_priv);
 
         present_fake_screen_init(screen);
     }
diff --git a/present/present_scrmode.c b/present/present_scrmode.c
new file mode 100644
index 0000000..76bc4ea
--- /dev/null
+++ b/present/present_scrmode.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include "present_priv.h"
+
+static uint64_t         present_event_id;
+static struct xorg_list present_exec_queue;
+static struct xorg_list present_flip_queue;
+
+static void
+present_scrmode_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
+
+static void
+present_scrmode_create_event_id(present_window_priv_ptr window_priv, present_vblank_ptr vblank)
+{
+    vblank->event_id = ++present_event_id;
+}
+
+static uint32_t
+present_scrmode_query_capabilities(present_screen_priv_ptr screen_priv)
+{
+    if (!screen_priv->info)
+        return 0;
+
+    return screen_priv->info->capabilities;
+}
+
+static RRCrtcPtr
+present_scrmode_get_crtc(present_screen_priv_ptr screen_priv, WindowPtr window)
+{
+    if (!screen_priv)
+        return NULL;
+
+    if (!screen_priv->info)
+        return NULL;
+
+    return (*screen_priv->info->get_crtc)(window);
+}
+
+static inline PixmapPtr
+present_scrmode_flip_pending_pixmap(ScreenPtr screen)
+{
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+
+    if (!screen_priv)
+        return NULL;
+
+    if (!screen_priv->flip_pending)
+        return NULL;
+
+    return screen_priv->flip_pending->pixmap;
+}
+
+static Bool
+present_scrmode_flip(RRCrtcPtr  crtc,
+                     uint64_t   event_id,
+                     uint64_t   target_msc,
+                     PixmapPtr  pixmap,
+                     Bool       sync_flip)
+{
+    ScreenPtr                   screen = 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);
+}
+
+static int
+present_scrmode_get_ust_msc(ScreenPtr screen, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
+{
+    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+
+    if (crtc == NULL)
+        return present_fake_get_ust_msc(screen, ust, msc);
+    else
+        return (*screen_priv->info->get_ust_msc)(crtc, ust, msc);
+}
+
+/*
+ * When the wait fence or previous flip is completed, it's time
+ * to re-try the request
+ */
+static void
+present_scrmode_re_execute(present_vblank_ptr vblank)
+{
+    uint64_t ust = 0, crtc_msc = 0;
+
+    if (vblank->crtc)
+        (void) present_scrmode_get_ust_msc(vblank->screen, vblank->crtc, &ust, &crtc_msc);
+
+    present_scrmode_execute(vblank, ust, crtc_msc);
+}
+
+static void
+present_scrmode_flip_try_ready(ScreenPtr screen)
+{
+    present_vblank_ptr vblank;
+
+    xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
+        if (vblank->queued) {
+            present_scrmode_re_execute(vblank);
+            return;
+        }
+    }
+}
+
+static void
+present_scrmode_flip_idle(ScreenPtr screen)
+{
+    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+
+    if (screen_priv->flip_pixmap) {
+        present_pixmap_idle(screen_priv->flip_pixmap, screen_priv->flip_window,
+                            screen_priv->flip_serial, screen_priv->flip_idle_fence);
+        if (screen_priv->flip_idle_fence)
+            present_fence_destroy(screen_priv->flip_idle_fence);
+
+        dixDestroyPixmap(screen_priv->flip_pixmap, screen_priv->flip_pixmap->drawable.id);
+        screen_priv->flip_crtc = NULL;
+        screen_priv->flip_window = NULL;
+        screen_priv->flip_serial = 0;
+        screen_priv->flip_pixmap = NULL;
+        screen_priv->flip_idle_fence = NULL;
+    }
+}
+
+void
+present_scrmode_restore_screen_pixmap(ScreenPtr screen)
+{
+    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+    PixmapPtr               screen_pixmap = (*screen->GetScreenPixmap)(screen);
+    PixmapPtr               flip_pixmap;
+    WindowPtr               flip_window;
+
+    if (screen_priv->flip_pending) {
+        flip_window = screen_priv->flip_pending->window;
+        flip_pixmap = screen_priv->flip_pending->pixmap;
+    } else {
+        flip_window = screen_priv->flip_window;
+        flip_pixmap = screen_priv->flip_pixmap;
+    }
+
+    assert (flip_pixmap);
+
+    /* Update the screen pixmap with the current flip pixmap contents
+     * Only do this the first time for a particular unflip operation, or
+     * we'll probably scribble over other windows
+     */
+    if (screen->root && screen->GetWindowPixmap(screen->root) == flip_pixmap)
+        present_copy_region(&screen_pixmap->drawable, flip_pixmap, NULL, 0, 0);
+
+    /* Switch back to using the screen pixmap now to avoid
+     * 2D applications drawing to the wrong pixmap.
+     */
+    if (flip_window)
+        present_set_tree_pixmap(flip_window, flip_pixmap, screen_pixmap);
+    if (screen->root)
+        present_set_tree_pixmap(screen->root, NULL, screen_pixmap);
+}
+
+void
+present_scrmode_set_abort_flip(ScreenPtr screen)
+{
+    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+
+    if (!screen_priv->flip_pending->abort_flip) {
+        present_scrmode_restore_screen_pixmap(screen);
+        screen_priv->flip_pending->abort_flip = TRUE;
+    }
+}
+
+static void
+present_scrmode_unflip(ScreenPtr screen)
+{
+    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+
+    assert (!screen_priv->unflip_event_id);
+    assert (!screen_priv->flip_pending);
+
+    present_scrmode_restore_screen_pixmap(screen);
+
+    screen_priv->unflip_event_id = ++present_event_id;
+    DebugPresent(("u %lld\n", screen_priv->unflip_event_id));
+    (*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id);
+}
+
+static void
+present_scrmode_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
+{
+    ScreenPtr                   screen = vblank->screen;
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+
+    DebugPresent(("\tn %lld %p %8lld: %08lx -> %08lx\n",
+                  vblank->event_id, vblank, vblank->target_msc,
+                  vblank->pixmap ? vblank->pixmap->drawable.id : 0,
+                  vblank->window ? vblank->window->drawable.id : 0));
+
+    assert (vblank == screen_priv->flip_pending);
+
+    present_scrmode_flip_idle(screen);
+
+    xorg_list_del(&vblank->event_queue);
+
+    /* Transfer reference for pixmap and fence from vblank to screen_priv */
+    screen_priv->flip_crtc = vblank->crtc;
+    screen_priv->flip_window = vblank->window;
+    screen_priv->flip_serial = vblank->serial;
+    screen_priv->flip_pixmap = vblank->pixmap;
+    screen_priv->flip_sync = vblank->sync_flip;
+    screen_priv->flip_idle_fence = vblank->idle_fence;
+
+    vblank->pixmap = NULL;
+    vblank->idle_fence = NULL;
+
+    screen_priv->flip_pending = NULL;
+
+    if (vblank->abort_flip)
+        present_scrmode_unflip(screen);
+
+    present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
+    present_vblank_destroy(vblank);
+
+    present_scrmode_flip_try_ready(screen);
+}
+
+void
+present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc)
+{
+    present_vblank_ptr  vblank;
+    int                 s;
+
+    if (!event_id)
+        return;
+    DebugPresent(("\te %lld ust %lld msc %lld\n", event_id, ust, msc));
+    xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) {
+        if (event_id == vblank->event_id) {
+            present_scrmode_execute(vblank, ust, msc);
+            return;
+        }
+    }
+    xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
+        if (vblank->event_id == event_id) {
+            if (vblank->queued) {
+                present_scrmode_execute(vblank, ust, msc);
+            } else {
+                assert(vblank->window);
+                present_scrmode_flip_notify(vblank, ust, msc);
+            }
+            return;
+        }
+    }
+
+    for (s = 0; s < screenInfo.numScreens; s++) {
+        ScreenPtr               screen = screenInfo.screens[s];
+        present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+
+        if (event_id == screen_priv->unflip_event_id) {
+            DebugPresent(("\tun %lld\n", event_id));
+            screen_priv->unflip_event_id = 0;
+            present_scrmode_flip_idle(screen);
+            present_scrmode_flip_try_ready(screen);
+            return;
+        }
+    }
+}
+
+static Bool
+present_scrmode_check_flip(RRCrtcPtr    crtc,
+                           WindowPtr    window,
+                           PixmapPtr    pixmap,
+                           Bool         sync_flip,
+                           RegionPtr    valid,
+                           int16_t      x_off,
+                           int16_t      y_off)
+{
+    ScreenPtr                   screen = window->drawable.pScreen;
+    PixmapPtr                   window_pixmap;
+    WindowPtr                   root = screen->root;
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+
+    if (!screen_priv)
+        return FALSE;
+
+    if (!screen_priv->info)
+        return FALSE;
+
+    if (!crtc)
+        return FALSE;
+
+    /* Check to see if the driver supports flips at all */
+    if (!screen_priv->info->flip)
+        return FALSE;
+
+    /* Source pixmap must align with window exactly */
+    if (x_off || y_off) {
+        return FALSE;
+    }
+
+    /* Make sure the window hasn't been redirected with Composite */
+    window_pixmap = screen->GetWindowPixmap(window);
+    if (window_pixmap != screen->GetScreenPixmap(screen) &&
+        window_pixmap != screen_priv->flip_pixmap &&
+        window_pixmap != present_scrmode_flip_pending_pixmap(screen))
+        return FALSE;
+
+    /* Check for full-screen window */
+    if (!RegionEqual(&window->clipList, &root->winSize)) {
+        return FALSE;
+    }
+
+    /* Make sure the area marked as valid fills the screen */
+    if (valid && !RegionEqual(valid, &root->winSize)) {
+        return FALSE;
+    }
+
+    /* Does the window match the pixmap exactly? */
+    if (window->drawable.x != 0 || window->drawable.y != 0)
+        return FALSE;
+    #ifdef COMPOSITE
+    if (window->drawable.x != pixmap->screen_x || window->drawable.y != pixmap->screen_y)
+        return FALSE;
+    #endif
+
+    if (window->drawable.width != pixmap->drawable.width ||
+            window->drawable.height != pixmap->drawable.height)
+        return FALSE;
+
+    /* Ask the driver for permission */
+    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;
+        }
+    }
+
+    return TRUE;
+}
+
+/*
+ * 'window' is being reconfigured. Check to see if it is involved
+ * in flipping and clean up as necessary
+ */
+static void
+present_scrmode_check_flip_window (WindowPtr window)
+{
+    ScreenPtr                   screen = window->drawable.pScreen;
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+    present_window_priv_ptr     window_priv = present_window_priv(window);
+    present_vblank_ptr          flip_pending;
+    present_vblank_ptr          vblank;
+
+    /* If this window hasn't ever been used with Present, it can't be
+     * flipping
+     */
+    if (!window_priv)
+        return;
+
+    if (screen_priv->unflip_event_id)
+        return;
+
+    flip_pending = screen_priv->flip_pending;
+
+    if (flip_pending) {
+        /*
+         * Check pending flip
+         */
+        if (flip_pending->window == window) {
+            if (!present_scrmode_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
+                                    flip_pending->sync_flip, NULL, 0, 0))
+                present_scrmode_set_abort_flip(screen);
+        }
+    } else {
+        /*
+         * Check current flip
+         */
+        if (window == screen_priv->flip_window) {
+            if (!present_scrmode_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0))
+                present_scrmode_unflip(screen);
+        }
+    }
+
+    /* Now check any queued vblanks */
+    xorg_list_for_each_entry(vblank, &window_priv->vblank_queue, window_list) {
+        if (vblank->queued && vblank->flip && !present_scrmode_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0)) {
+            vblank->flip = FALSE;
+            if (vblank->sync_flip)
+                vblank->requeue = TRUE;
+        }
+    }
+}
+
+/*
+ * Once the required MSC has been reached, execute the pending request.
+ *
+ * For requests to actually present something, either blt contents to
+ * the screen or queue a frame buffer swap.
+ *
+ * For requests to just get the current MSC/UST combo, skip that part and
+ * go straight to event delivery
+ */
+static void
+present_scrmode_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
+{
+    WindowPtr                   window = vblank->window;
+    ScreenPtr                   screen = window->drawable.pScreen;
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+
+    if (present_execute_wait(vblank, crtc_msc))
+        return;
+
+    if (vblank->flip && vblank->pixmap && vblank->window) {
+        if (screen_priv->flip_pending || screen_priv->unflip_event_id) {
+            DebugPresent(("\tr %lld %p (pending %p unflip %lld)\n",
+                          vblank->event_id, vblank,
+                          screen_priv->flip_pending, screen_priv->unflip_event_id));
+
+            xorg_list_del(&vblank->event_queue);
+            xorg_list_append(&vblank->event_queue, &present_flip_queue);
+            vblank->flip_ready = TRUE;
+            return;
+        }
+    }
+
+    xorg_list_del(&vblank->event_queue);
+    xorg_list_del(&vblank->window_list);
+    vblank->queued = FALSE;
+
+    if (vblank->pixmap && vblank->window) {
+
+        if (vblank->flip) {
+            RegionPtr damage;
+
+            DebugPresent(("\tf %lld %p %8lld: %08lx -> %08lx\n",
+                          vblank->event_id, vblank, crtc_msc,
+                          vblank->pixmap->drawable.id, vblank->window->drawable.id));
+
+            /* Prepare to flip by placing it in the flip queue
+             */
+            xorg_list_add(&vblank->event_queue, &present_flip_queue);
+            screen_priv->flip_pending = vblank;
+
+            /* Try to flip
+             */
+
+            if (present_scrmode_flip(vblank->crtc, vblank->event_id, vblank->target_msc, vblank->pixmap, vblank->sync_flip)) {
+                /* Fix window pixmaps:
+                 *  1) Restore previous flip window pixmap
+                 *  2) Set current flip window pixmap to the new pixmap
+                 */
+                if (screen_priv->flip_window && screen_priv->flip_window != window)
+                    present_set_tree_pixmap(screen_priv->flip_window,
+                                            screen_priv->flip_pixmap,
+                                            (*screen->GetScreenPixmap)(screen));
+                present_set_tree_pixmap(vblank->window, NULL, vblank->pixmap);
+                present_set_tree_pixmap(screen->root, NULL, vblank->pixmap);
+
+                /* Report update region as damaged
+                 */
+                if (vblank->update) {
+                    damage = vblank->update;
+                    RegionIntersect(damage, damage, &window->clipList);
+                } else
+                    damage = &window->clipList;
+
+                DamageDamageRegion(&vblank->window->drawable, damage);
+
+                return;
+            }
+
+            xorg_list_del(&vblank->event_queue);
+            /* Oops, flip failed. Clear the flip_pending field
+              */
+            screen_priv->flip_pending = NULL;
+            vblank->flip = FALSE;
+        }
+        DebugPresent(("\tc %p %8lld: %08lx -> %08lx\n", vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
+
+        if (screen_priv->flip_pending) {
+            /* Check pending flip
+             */
+            if (window == screen_priv->flip_pending->window)
+                present_scrmode_set_abort_flip(screen);
+        } else if (!screen_priv->unflip_event_id) {
+
+            /* Check current flip
+             */
+            if (window == screen_priv->flip_window)
+                present_scrmode_unflip(screen);
+        }
+
+        present_execute_copy(vblank, crtc_msc);
+
+        if (vblank->queued) {
+            xorg_list_add(&vblank->event_queue, &present_exec_queue);
+            xorg_list_append(&vblank->window_list,
+                             &present_get_window_priv(window, TRUE)->vblank_queue);
+            return;
+        }
+    }
+
+    present_execute_post(vblank, ust, crtc_msc);
+}
+
+static int
+present_scrmode_queue_vblank(ScreenPtr screen,
+                             WindowPtr window,
+                             RRCrtcPtr crtc,
+                             uint64_t event_id,
+                             uint64_t msc)
+{
+    Bool ret;
+
+    if (crtc == NULL)
+        ret = present_fake_queue_vblank(screen, event_id, msc);
+    else
+    {
+        present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+        ret = (*screen_priv->info->queue_vblank) (crtc, event_id, msc);
+    }
+    return ret;
+}
+
+static uint64_t
+present_scrmode_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc)
+{
+    present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
+
+    if (crtc != window_priv->crtc) {
+        uint64_t        old_ust, old_msc;
+
+        if (window_priv->crtc == PresentCrtcNeverSet) {
+            window_priv->msc_offset = 0;
+        } else {
+            /* The old CRTC may have been turned off, in which case
+             * we'll just use whatever previous MSC we'd seen from this CRTC
+             */
+
+            if (present_scrmode_get_ust_msc(window->drawable.pScreen, window_priv->crtc, &old_ust, &old_msc) != Success)
+                old_msc = window_priv->msc;
+
+            window_priv->msc_offset += new_msc - old_msc;
+        }
+        window_priv->crtc = crtc;
+    }
+
+    return window_msc + window_priv->msc_offset;
+}
+
+static int
+present_scrmode_present_pixmap(present_window_priv_ptr window_priv,
+                               PixmapPtr pixmap,
+                               CARD32 serial,
+                               RegionPtr valid,
+                               RegionPtr update,
+                               int16_t x_off,
+                               int16_t y_off,
+                               RRCrtcPtr target_crtc,
+                               SyncFence *wait_fence,
+                               SyncFence *idle_fence,
+                               uint32_t options,
+                               uint64_t window_msc,
+                               uint64_t divisor,
+                               uint64_t remainder,
+                               present_notify_ptr notifies,
+                               int num_notifies)
+{
+    WindowPtr                   window = window_priv->window;
+    ScreenPtr                   screen = window->drawable.pScreen;
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+    uint64_t                    ust = 0;
+    uint64_t                    target_msc;
+    uint64_t                    crtc_msc = 0;
+    present_vblank_ptr          vblank, tmp;
+
+    if (!screen_priv || !screen_priv->info)
+        target_crtc = NULL;
+    else if (!target_crtc) {
+        /* Update the CRTC if we have a pixmap or we don't have a CRTC
+         */
+        if (!pixmap)
+            target_crtc = window_priv->crtc;
+
+        if (!target_crtc || target_crtc == PresentCrtcNeverSet)
+            target_crtc = present_scrmode_get_crtc(screen_priv, window);
+    }
+
+    if (present_scrmode_get_ust_msc(screen, target_crtc, &ust, &crtc_msc) == Success) {
+        /* Stash the current MSC away in case we need it later
+         */
+        window_priv->msc = crtc_msc;
+    }
+
+    target_msc = present_scrmode_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
+
+    present_adjust_timings(options,
+                           &crtc_msc,
+                           &target_msc,
+                           divisor,
+                           remainder);
+
+    /*
+     * Look for a matching presentation already on the list and
+     * don't bother doing the previous one if this one will overwrite it
+     * in the same frame
+     */
+    if (!update && pixmap) {
+        xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank_queue, window_list) {
+
+            if (!vblank->pixmap)
+                continue;
+
+            if (!vblank->queued)
+                continue;
+
+            if (vblank->target_msc != target_msc)
+                continue;
+
+            if (vblank->crtc != target_crtc)
+                continue;
+
+            present_vblank_scrap(vblank);
+            if (vblank->flip_ready)
+                present_scrmode_re_execute(vblank);
+        }
+    }
+
+    vblank = present_vblank_create(window_priv,
+                                   pixmap,
+                                   serial,
+                                   valid,
+                                   update,
+                                   x_off,
+                                   y_off,
+                                   target_crtc,
+                                   wait_fence,
+                                   idle_fence,
+                                   options,
+                                   screen_priv->info ? &screen_priv->info->capabilities : NULL,
+                                   notifies,
+                                   num_notifies,
+                                   &target_msc,
+                                   crtc_msc);
+
+    if (!vblank)
+        return BadAlloc;
+
+    xorg_list_append(&vblank->event_queue, &present_exec_queue);
+    vblank->queued = TRUE;
+    if (crtc_msc < target_msc) {
+        if (present_scrmode_queue_vblank(screen, window, target_crtc, vblank->event_id, target_msc) == Success) {
+            return Success;
+        }
+        DebugPresent(("present_queue_vblank failed\n"));
+    }
+
+    present_scrmode_execute(vblank, ust, crtc_msc);
+
+    return Success;
+}
+
+static void
+present_scrmode_flush(WindowPtr window)
+{
+    ScreenPtr                   screen = window->drawable.pScreen;
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+
+    if (!screen_priv)
+        return;
+
+    if (!screen_priv->info)
+        return;
+
+    (*screen_priv->info->flush) (window);
+}
+
+static void
+present_scrmode_abort_vblank(ScreenPtr screen, WindowPtr window, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
+{
+    present_vblank_ptr  vblank;
+
+    if (crtc == NULL)
+        present_fake_abort_vblank(screen, event_id, msc);
+    else
+    {
+        present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+
+        (*screen_priv->info->abort_vblank) (crtc, event_id, msc);
+    }
+
+    xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) {
+        int64_t match = event_id - vblank->event_id;
+        if (match == 0) {
+            xorg_list_del(&vblank->event_queue);
+            vblank->queued = FALSE;
+            return;
+        }
+        if (match < 0)
+            break;
+    }
+    xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
+        if (vblank->event_id == event_id) {
+            xorg_list_del(&vblank->event_queue);
+            vblank->queued = FALSE;
+            return;
+        }
+    }
+}
+
+static void
+present_scrmode_flip_destroy(ScreenPtr screen)
+{
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+
+    /* Reset window pixmaps back to the screen pixmap */
+    if (screen_priv->flip_pending)
+        present_scrmode_set_abort_flip(screen);
+
+    /* Drop reference to any pending flip or unflip pixmaps. */
+    present_scrmode_flip_idle(screen);
+}
+
+void
+present_scrmode_init_scrmode(present_screen_priv_ptr screen_priv)
+{
+    screen_priv->query_capabilities =   &present_scrmode_query_capabilities;
+    screen_priv->get_crtc           =   &present_scrmode_get_crtc;
+
+    screen_priv->check_flip         =   &present_scrmode_check_flip;
+    screen_priv->check_flip_window  =   &present_scrmode_check_flip_window;
+
+    screen_priv->present_pixmap     =   &present_scrmode_present_pixmap;
+    screen_priv->create_event_id    =   &present_scrmode_create_event_id;
+    screen_priv->queue_vblank       =   &present_scrmode_queue_vblank;
+    screen_priv->flush              =   &present_scrmode_flush;
+    screen_priv->re_execute         =   &present_scrmode_re_execute;
+
+    screen_priv->abort_vblank       =   &present_scrmode_abort_vblank;
+    screen_priv->flips_destroy      =   &present_scrmode_flip_destroy;
+}
+
+Bool
+present_init(void)
+{
+    xorg_list_init(&present_exec_queue);
+    xorg_list_init(&present_flip_queue);
+    present_fake_queue_init();
+    return TRUE;
+}
-- 
2.7.4



More information about the xorg-devel mailing list