Home | History | Annotate | Line # | Download | only in present
      1 /*
      2  * Copyright  2013 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that copyright
      7  * notice and this permission notice appear in supporting documentation, and
      8  * that the name of the copyright holders not be used in advertising or
      9  * publicity pertaining to distribution of the software without specific,
     10  * written prior permission.  The copyright holders make no representations
     11  * about the suitability of this software for any purpose.  It is provided "as
     12  * is" without express or implied warranty.
     13  *
     14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     20  * OF THIS SOFTWARE.
     21  */
     22 
     23 #include "present_priv.h"
     24 #include <misync.h>
     25 #include <misyncstr.h>
     26 #ifdef MONOTONIC_CLOCK
     27 #include <time.h>
     28 #endif
     29 
     30 /*
     31  * Screen flip mode
     32  *
     33  * Provides the default mode for drivers, that do not
     34  * support flips and the full screen flip mode.
     35  *
     36  */
     37 
     38 static uint64_t present_scmd_event_id;
     39 
     40 static struct xorg_list present_exec_queue;
     41 static struct xorg_list present_flip_queue;
     42 
     43 static void
     44 present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
     45 
     46 static inline PixmapPtr
     47 present_flip_pending_pixmap(ScreenPtr screen)
     48 {
     49     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
     50 
     51     if (!screen_priv)
     52         return NULL;
     53 
     54     if (!screen_priv->flip_pending)
     55         return NULL;
     56 
     57     return screen_priv->flip_pending->pixmap;
     58 }
     59 
     60 static Bool
     61 present_check_flip(RRCrtcPtr            crtc,
     62                    WindowPtr            window,
     63                    PixmapPtr            pixmap,
     64                    Bool                 sync_flip,
     65                    RegionPtr            valid,
     66                    int16_t              x_off,
     67                    int16_t              y_off,
     68                    PresentFlipReason   *reason)
     69 {
     70     ScreenPtr                   screen = window->drawable.pScreen;
     71     PixmapPtr                   window_pixmap;
     72     WindowPtr                   root = screen->root;
     73     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
     74 
     75     if (crtc) {
     76        screen_priv = present_screen_priv(crtc->pScreen);
     77     }
     78     if (reason)
     79         *reason = PRESENT_FLIP_REASON_UNKNOWN;
     80 
     81     if (!screen_priv)
     82         return FALSE;
     83 
     84     if (!screen_priv->info)
     85         return FALSE;
     86 
     87     if (!crtc)
     88         return FALSE;
     89 
     90     /* Check to see if the driver supports flips at all */
     91     if (!screen_priv->info->flip)
     92         return FALSE;
     93 
     94     /* Make sure the window hasn't been redirected with Composite */
     95     window_pixmap = screen->GetWindowPixmap(window);
     96     if (window_pixmap != screen->GetScreenPixmap(screen) &&
     97         window_pixmap != screen_priv->flip_pixmap &&
     98         window_pixmap != present_flip_pending_pixmap(screen))
     99         return FALSE;
    100 
    101     /* Check for full-screen window */
    102     if (!RegionEqual(&window->clipList, &root->winSize)) {
    103         return FALSE;
    104     }
    105 
    106     /* Source pixmap must align with window exactly */
    107     if (x_off || y_off) {
    108         return FALSE;
    109     }
    110 
    111     /* Make sure the area marked as valid fills the screen */
    112     if (valid && !RegionEqual(valid, &root->winSize)) {
    113         return FALSE;
    114     }
    115 
    116     /* Does the window match the pixmap exactly? */
    117     if (window->drawable.x != 0 || window->drawable.y != 0 ||
    118 #ifdef COMPOSITE
    119         window->drawable.x != pixmap->screen_x || window->drawable.y != pixmap->screen_y ||
    120 #endif
    121         window->drawable.width != pixmap->drawable.width ||
    122         window->drawable.height != pixmap->drawable.height) {
    123         return FALSE;
    124     }
    125 
    126     /* Ask the driver for permission */
    127     if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
    128         if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
    129             DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
    130             return FALSE;
    131         }
    132     } else if (screen_priv->info->check_flip) {
    133         if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
    134             DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
    135             return FALSE;
    136         }
    137     }
    138 
    139     return TRUE;
    140 }
    141 
    142 static Bool
    143 present_flip(RRCrtcPtr crtc,
    144              uint64_t event_id,
    145              uint64_t target_msc,
    146              PixmapPtr pixmap,
    147              Bool sync_flip)
    148 {
    149     ScreenPtr                   screen = crtc->pScreen;
    150     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    151 
    152     return (*screen_priv->info->flip) (crtc, event_id, target_msc, pixmap, sync_flip);
    153 }
    154 
    155 static RRCrtcPtr
    156 present_scmd_get_crtc(present_screen_priv_ptr screen_priv, WindowPtr window)
    157 {
    158     if (!screen_priv->info)
    159         return NULL;
    160 
    161     if (!screen_priv->info->get_crtc)
    162         return NULL;
    163 
    164     return (*screen_priv->info->get_crtc)(window);
    165 }
    166 
    167 static uint32_t
    168 present_scmd_query_capabilities(present_screen_priv_ptr screen_priv)
    169 {
    170     if (!screen_priv->info)
    171         return 0;
    172 
    173     return screen_priv->info->capabilities;
    174 }
    175 
    176 static int
    177 present_get_ust_msc(ScreenPtr screen, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
    178 {
    179     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    180     present_screen_priv_ptr     crtc_screen_priv = screen_priv;
    181     if (crtc)
    182         crtc_screen_priv = present_screen_priv(crtc->pScreen);
    183 
    184     if (crtc == NULL)
    185         return present_fake_get_ust_msc(screen, ust, msc);
    186     else
    187         return (*crtc_screen_priv->info->get_ust_msc)(crtc, ust, msc);
    188 }
    189 
    190 static void
    191 present_flush(WindowPtr window)
    192 {
    193     ScreenPtr                   screen = window->drawable.pScreen;
    194     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    195 
    196     if (!screen_priv)
    197         return;
    198 
    199     if (!screen_priv->info)
    200         return;
    201 
    202     if (!screen_priv->info->flush)
    203         return;
    204 
    205     (*screen_priv->info->flush) (window);
    206 }
    207 
    208 static int
    209 present_queue_vblank(ScreenPtr screen,
    210                      WindowPtr window,
    211                      RRCrtcPtr crtc,
    212                      uint64_t event_id,
    213                      uint64_t msc)
    214 {
    215     Bool                        ret;
    216 
    217     if (crtc == NULL)
    218         ret = present_fake_queue_vblank(screen, event_id, msc);
    219     else
    220     {
    221         present_screen_priv_ptr     screen_priv = present_screen_priv(crtc->pScreen);
    222         ret = (*screen_priv->info->queue_vblank) (crtc, event_id, msc);
    223     }
    224     return ret;
    225 }
    226 
    227 /*
    228  * When the wait fence or previous flip is completed, it's time
    229  * to re-try the request
    230  */
    231 static void
    232 present_re_execute(present_vblank_ptr vblank)
    233 {
    234     uint64_t            ust = 0, crtc_msc = 0;
    235 
    236     if (vblank->crtc)
    237         (void) present_get_ust_msc(vblank->screen, vblank->crtc, &ust, &crtc_msc);
    238 
    239     present_execute(vblank, ust, crtc_msc);
    240 }
    241 
    242 static void
    243 present_flip_try_ready(ScreenPtr screen)
    244 {
    245     present_vblank_ptr  vblank;
    246 
    247     xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
    248         if (vblank->queued) {
    249             present_re_execute(vblank);
    250             return;
    251         }
    252     }
    253 }
    254 
    255 static void
    256 present_flip_idle(ScreenPtr screen)
    257 {
    258     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    259 
    260     if (screen_priv->flip_pixmap) {
    261         present_pixmap_idle(screen_priv->flip_pixmap, screen_priv->flip_window,
    262                             screen_priv->flip_serial, screen_priv->flip_idle_fence);
    263         if (screen_priv->flip_idle_fence)
    264             present_fence_destroy(screen_priv->flip_idle_fence);
    265         dixDestroyPixmap(screen_priv->flip_pixmap, screen_priv->flip_pixmap->drawable.id);
    266         screen_priv->flip_crtc = NULL;
    267         screen_priv->flip_window = NULL;
    268         screen_priv->flip_serial = 0;
    269         screen_priv->flip_pixmap = NULL;
    270         screen_priv->flip_idle_fence = NULL;
    271     }
    272 }
    273 
    274 void
    275 present_restore_screen_pixmap(ScreenPtr screen)
    276 {
    277     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    278     PixmapPtr screen_pixmap = (*screen->GetScreenPixmap)(screen);
    279     PixmapPtr flip_pixmap;
    280     WindowPtr flip_window;
    281 
    282     if (screen_priv->flip_pending) {
    283         flip_window = screen_priv->flip_pending->window;
    284         flip_pixmap = screen_priv->flip_pending->pixmap;
    285     } else {
    286         flip_window = screen_priv->flip_window;
    287         flip_pixmap = screen_priv->flip_pixmap;
    288     }
    289 
    290     assert (flip_pixmap);
    291 
    292     /* Update the screen pixmap with the current flip pixmap contents
    293      * Only do this the first time for a particular unflip operation, or
    294      * we'll probably scribble over other windows
    295      */
    296     if (screen->root && screen->GetWindowPixmap(screen->root) == flip_pixmap)
    297         present_copy_region(&screen_pixmap->drawable, flip_pixmap, NULL, 0, 0);
    298 
    299     /* Switch back to using the screen pixmap now to avoid
    300      * 2D applications drawing to the wrong pixmap.
    301      */
    302     if (flip_window)
    303         present_set_tree_pixmap(flip_window, flip_pixmap, screen_pixmap);
    304     if (screen->root)
    305         present_set_tree_pixmap(screen->root, NULL, screen_pixmap);
    306 }
    307 
    308 void
    309 present_set_abort_flip(ScreenPtr screen)
    310 {
    311     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    312 
    313     if (!screen_priv->flip_pending->abort_flip) {
    314         present_restore_screen_pixmap(screen);
    315         screen_priv->flip_pending->abort_flip = TRUE;
    316     }
    317 }
    318 
    319 static void
    320 present_unflip(ScreenPtr screen)
    321 {
    322     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    323 
    324     assert (!screen_priv->unflip_event_id);
    325     assert (!screen_priv->flip_pending);
    326 
    327     present_restore_screen_pixmap(screen);
    328 
    329     screen_priv->unflip_event_id = ++present_scmd_event_id;
    330     DebugPresent(("u %" PRIu64 "\n", screen_priv->unflip_event_id));
    331     (*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id);
    332 }
    333 
    334 static void
    335 present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
    336 {
    337     ScreenPtr                   screen = vblank->screen;
    338     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    339 
    340     DebugPresent(("\tn %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
    341                   vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc,
    342                   vblank->pixmap ? vblank->pixmap->drawable.id : 0,
    343                   vblank->window ? vblank->window->drawable.id : 0));
    344 
    345     assert (vblank == screen_priv->flip_pending);
    346 
    347     present_flip_idle(screen);
    348 
    349     xorg_list_del(&vblank->event_queue);
    350 
    351     /* Transfer reference for pixmap and fence from vblank to screen_priv */
    352     screen_priv->flip_crtc = vblank->crtc;
    353     screen_priv->flip_window = vblank->window;
    354     screen_priv->flip_serial = vblank->serial;
    355     screen_priv->flip_pixmap = vblank->pixmap;
    356     screen_priv->flip_sync = vblank->sync_flip;
    357     screen_priv->flip_idle_fence = vblank->idle_fence;
    358 
    359     vblank->pixmap = NULL;
    360     vblank->idle_fence = NULL;
    361 
    362     screen_priv->flip_pending = NULL;
    363 
    364     if (vblank->abort_flip)
    365         present_unflip(screen);
    366 
    367     present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
    368     present_vblank_destroy(vblank);
    369 
    370     present_flip_try_ready(screen);
    371 }
    372 
    373 void
    374 present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc)
    375 {
    376     present_vblank_ptr  vblank;
    377     int                 s;
    378 
    379     if (!event_id)
    380         return;
    381     DebugPresent(("\te %" PRIu64 " ust %" PRIu64 " msc %" PRIu64 "\n", event_id, ust, msc));
    382     xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) {
    383         int64_t match = event_id - vblank->event_id;
    384         if (match == 0) {
    385             present_execute(vblank, ust, msc);
    386             return;
    387         }
    388     }
    389     xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
    390         if (vblank->event_id == event_id) {
    391             if (vblank->queued)
    392                 present_execute(vblank, ust, msc);
    393             else
    394                 present_flip_notify(vblank, ust, msc);
    395             return;
    396         }
    397     }
    398 
    399     for (s = 0; s < screenInfo.numScreens; s++) {
    400         ScreenPtr               screen = screenInfo.screens[s];
    401         present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    402 
    403         if (event_id == screen_priv->unflip_event_id) {
    404             DebugPresent(("\tun %" PRIu64 "\n", event_id));
    405             screen_priv->unflip_event_id = 0;
    406             present_flip_idle(screen);
    407             present_flip_try_ready(screen);
    408             return;
    409         }
    410     }
    411 }
    412 
    413 /*
    414  * 'window' is being reconfigured. Check to see if it is involved
    415  * in flipping and clean up as necessary
    416  */
    417 static void
    418 present_check_flip_window (WindowPtr window)
    419 {
    420     ScreenPtr                   screen = window->drawable.pScreen;
    421     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    422     present_window_priv_ptr     window_priv = present_window_priv(window);
    423     present_vblank_ptr          flip_pending = screen_priv->flip_pending;
    424     present_vblank_ptr          vblank;
    425     PresentFlipReason           reason;
    426 
    427     /* If this window hasn't ever been used with Present, it can't be
    428      * flipping
    429      */
    430     if (!window_priv)
    431         return;
    432 
    433     if (screen_priv->unflip_event_id)
    434         return;
    435 
    436     if (flip_pending) {
    437         /*
    438          * Check pending flip
    439          */
    440         if (flip_pending->window == window) {
    441             if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
    442                                     flip_pending->sync_flip, NULL, 0, 0, NULL))
    443                 present_set_abort_flip(screen);
    444         }
    445     } else {
    446         /*
    447          * Check current flip
    448          */
    449         if (window == screen_priv->flip_window) {
    450             if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0, NULL))
    451                 present_unflip(screen);
    452         }
    453     }
    454 
    455     /* Now check any queued vblanks */
    456     xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
    457         if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) {
    458             vblank->flip = FALSE;
    459             vblank->reason = reason;
    460             if (vblank->sync_flip)
    461                 vblank->exec_msc = vblank->target_msc;
    462         }
    463     }
    464 }
    465 
    466 static Bool
    467 present_scmd_can_window_flip(WindowPtr window)
    468 {
    469     ScreenPtr                   screen = window->drawable.pScreen;
    470     PixmapPtr                   window_pixmap;
    471     WindowPtr                   root = screen->root;
    472     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    473 
    474     if (!screen_priv)
    475         return FALSE;
    476 
    477     if (!screen_priv->info)
    478         return FALSE;
    479 
    480     /* Check to see if the driver supports flips at all */
    481     if (!screen_priv->info->flip)
    482         return FALSE;
    483 
    484     /* Make sure the window hasn't been redirected with Composite */
    485     window_pixmap = screen->GetWindowPixmap(window);
    486     if (window_pixmap != screen->GetScreenPixmap(screen) &&
    487         window_pixmap != screen_priv->flip_pixmap &&
    488         window_pixmap != present_flip_pending_pixmap(screen))
    489         return FALSE;
    490 
    491     /* Check for full-screen window */
    492     if (!RegionEqual(&window->clipList, &root->winSize)) {
    493         return FALSE;
    494     }
    495 
    496     /* Does the window match the pixmap exactly? */
    497     if (window->drawable.x != 0 || window->drawable.y != 0) {
    498         return FALSE;
    499     }
    500 
    501     return TRUE;
    502 }
    503 
    504 /*
    505  * Clean up any pending or current flips for this window
    506  */
    507 static void
    508 present_scmd_clear_window_flip(WindowPtr window)
    509 {
    510     ScreenPtr                   screen = window->drawable.pScreen;
    511     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    512     present_vblank_ptr          flip_pending = screen_priv->flip_pending;
    513 
    514     if (flip_pending && flip_pending->window == window) {
    515         present_set_abort_flip(screen);
    516         flip_pending->window = NULL;
    517     }
    518     if (screen_priv->flip_window == window) {
    519         present_restore_screen_pixmap(screen);
    520         screen_priv->flip_window = NULL;
    521     }
    522 }
    523 
    524 /*
    525  * Once the required MSC has been reached, execute the pending request.
    526  *
    527  * For requests to actually present something, either blt contents to
    528  * the screen or queue a frame buffer swap.
    529  *
    530  * For requests to just get the current MSC/UST combo, skip that part and
    531  * go straight to event delivery
    532  */
    533 
    534 static void
    535 present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
    536 {
    537     WindowPtr                   window = vblank->window;
    538     ScreenPtr                   screen = window->drawable.pScreen;
    539     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    540     if (vblank && vblank->crtc) {
    541         screen_priv=present_screen_priv(vblank->crtc->pScreen);
    542     }
    543 
    544     if (present_execute_wait(vblank, crtc_msc))
    545         return;
    546 
    547     if (vblank->flip && vblank->pixmap && vblank->window) {
    548         if (screen_priv->flip_pending || screen_priv->unflip_event_id) {
    549             DebugPresent(("\tr %" PRIu64 " %p (pending %p unflip %" PRIu64 ")\n",
    550                           vblank->event_id, vblank,
    551                           screen_priv->flip_pending, screen_priv->unflip_event_id));
    552             xorg_list_del(&vblank->event_queue);
    553             xorg_list_append(&vblank->event_queue, &present_flip_queue);
    554             vblank->flip_ready = TRUE;
    555             return;
    556         }
    557     }
    558 
    559     xorg_list_del(&vblank->event_queue);
    560     xorg_list_del(&vblank->window_list);
    561     vblank->queued = FALSE;
    562 
    563     if (vblank->pixmap && vblank->window) {
    564 
    565         if (vblank->flip) {
    566 
    567             DebugPresent(("\tf %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
    568                           vblank->event_id, vblank, crtc_msc,
    569                           vblank->pixmap->drawable.id, vblank->window->drawable.id));
    570 
    571             /* Prepare to flip by placing it in the flip queue and
    572              * and sticking it into the flip_pending field
    573              */
    574             screen_priv->flip_pending = vblank;
    575 
    576             xorg_list_add(&vblank->event_queue, &present_flip_queue);
    577             /* Try to flip
    578              */
    579             if (present_flip(vblank->crtc, vblank->event_id, vblank->target_msc, vblank->pixmap, vblank->sync_flip)) {
    580                 RegionPtr damage;
    581 
    582                 /* Fix window pixmaps:
    583                  *  1) Restore previous flip window pixmap
    584                  *  2) Set current flip window pixmap to the new pixmap
    585                  */
    586                 if (screen_priv->flip_window && screen_priv->flip_window != window)
    587                     present_set_tree_pixmap(screen_priv->flip_window,
    588                                             screen_priv->flip_pixmap,
    589                                             (*screen->GetScreenPixmap)(screen));
    590                 present_set_tree_pixmap(vblank->window, NULL, vblank->pixmap);
    591                 present_set_tree_pixmap(screen->root, NULL, vblank->pixmap);
    592 
    593                 /* Report update region as damaged
    594                  */
    595                 if (vblank->update) {
    596                     damage = vblank->update;
    597                     RegionIntersect(damage, damage, &window->clipList);
    598                 } else
    599                     damage = &window->clipList;
    600 
    601                 DamageDamageRegion(&vblank->window->drawable, damage);
    602                 return;
    603             }
    604 
    605             xorg_list_del(&vblank->event_queue);
    606             /* Oops, flip failed. Clear the flip_pending field
    607               */
    608             screen_priv->flip_pending = NULL;
    609             vblank->flip = FALSE;
    610             vblank->exec_msc = vblank->target_msc;
    611         }
    612         DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
    613                       vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
    614         if (screen_priv->flip_pending) {
    615 
    616             /* Check pending flip
    617              */
    618             if (window == screen_priv->flip_pending->window)
    619                 present_set_abort_flip(screen);
    620         } else if (!screen_priv->unflip_event_id) {
    621 
    622             /* Check current flip
    623              */
    624             if (window == screen_priv->flip_window)
    625                 present_unflip(screen);
    626         }
    627 
    628         present_execute_copy(vblank, crtc_msc);
    629 
    630         if (vblank->queued) {
    631             xorg_list_add(&vblank->event_queue, &present_exec_queue);
    632             xorg_list_append(&vblank->window_list,
    633                              &present_get_window_priv(window, TRUE)->vblank);
    634             return;
    635         }
    636     }
    637 
    638     present_execute_post(vblank, ust, crtc_msc);
    639 }
    640 
    641 static void
    642 present_scmd_update_window_crtc(WindowPtr window, RRCrtcPtr crtc, uint64_t new_msc)
    643 {
    644     present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
    645     uint64_t                old_ust, old_msc;
    646 
    647     /* Crtc unchanged, no offset. */
    648     if (crtc == window_priv->crtc)
    649         return;
    650 
    651     /* No crtc earlier to offset against, just set the crtc. */
    652     if (window_priv->crtc == PresentCrtcNeverSet) {
    653         window_priv->crtc = crtc;
    654         return;
    655     }
    656 
    657     /* Crtc may have been turned off or be destroyed, just use whatever previous MSC we'd seen from this CRTC. */
    658     if (!RRCrtcExists(window->drawable.pScreen, window_priv->crtc) ||
    659         present_get_ust_msc(window->drawable.pScreen, window_priv->crtc, &old_ust, &old_msc) != Success)
    660         old_msc = window_priv->msc;
    661 
    662     window_priv->msc_offset += new_msc - old_msc;
    663     window_priv->crtc = crtc;
    664 }
    665 
    666 static int
    667 present_scmd_pixmap(WindowPtr window,
    668                     PixmapPtr pixmap,
    669                     CARD32 serial,
    670                     RegionPtr valid,
    671                     RegionPtr update,
    672                     int16_t x_off,
    673                     int16_t y_off,
    674                     RRCrtcPtr target_crtc,
    675                     SyncFence *wait_fence,
    676                     SyncFence *idle_fence,
    677                     uint32_t options,
    678                     uint64_t target_window_msc,
    679                     uint64_t divisor,
    680                     uint64_t remainder,
    681                     present_notify_ptr notifies,
    682                     int num_notifies)
    683 {
    684     uint64_t                    ust = 0;
    685     uint64_t                    target_msc;
    686     uint64_t                    crtc_msc = 0;
    687     int                         ret;
    688     present_vblank_ptr          vblank, tmp;
    689     ScreenPtr                   screen = window->drawable.pScreen;
    690     present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
    691     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    692 
    693     if (!window_priv)
    694         return BadAlloc;
    695 
    696     if (!screen_priv || !screen_priv->info)
    697         target_crtc = NULL;
    698     else if (!target_crtc) {
    699         /* Update the CRTC if we have a pixmap or we don't have a CRTC
    700          */
    701         if (!pixmap)
    702             target_crtc = window_priv->crtc;
    703 
    704         if (!target_crtc || target_crtc == PresentCrtcNeverSet)
    705             target_crtc = present_get_crtc(window);
    706     }
    707 
    708     ret = present_get_ust_msc(screen, target_crtc, &ust, &crtc_msc);
    709 
    710     present_scmd_update_window_crtc(window, target_crtc, crtc_msc);
    711 
    712     if (ret == Success) {
    713         /* Stash the current MSC away in case we need it later
    714          */
    715         window_priv->msc = crtc_msc;
    716     }
    717 
    718     target_msc = present_get_target_msc(target_window_msc + window_priv->msc_offset,
    719                                         crtc_msc,
    720                                         divisor,
    721                                         remainder,
    722                                         options);
    723 
    724     /*
    725      * Look for a matching presentation already on the list and
    726      * don't bother doing the previous one if this one will overwrite it
    727      * in the same frame
    728      */
    729 
    730     if (!update && pixmap) {
    731         xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
    732 
    733             if (!vblank->pixmap)
    734                 continue;
    735 
    736             if (!vblank->queued)
    737                 continue;
    738 
    739             if (vblank->crtc != target_crtc || vblank->target_msc != target_msc)
    740                 continue;
    741 
    742             present_vblank_scrap(vblank);
    743             if (vblank->flip_ready)
    744                 present_re_execute(vblank);
    745         }
    746     }
    747 
    748     vblank = present_vblank_create(window,
    749                                    pixmap,
    750                                    serial,
    751                                    valid,
    752                                    update,
    753                                    x_off,
    754                                    y_off,
    755                                    target_crtc,
    756                                    wait_fence,
    757                                    idle_fence,
    758                                    options,
    759                                    screen_priv->info ? screen_priv->info->capabilities : 0,
    760                                    notifies,
    761                                    num_notifies,
    762                                    target_msc,
    763                                    crtc_msc);
    764 
    765     if (!vblank)
    766         return BadAlloc;
    767 
    768     vblank->event_id = ++present_scmd_event_id;
    769 
    770     if (vblank->flip && vblank->sync_flip)
    771         vblank->exec_msc--;
    772 
    773     xorg_list_append(&vblank->event_queue, &present_exec_queue);
    774     vblank->queued = TRUE;
    775     if (msc_is_after(vblank->exec_msc, crtc_msc)) {
    776         ret = present_queue_vblank(screen, window, target_crtc, vblank->event_id, vblank->exec_msc);
    777         if (ret == Success)
    778             return Success;
    779 
    780         DebugPresent(("present_queue_vblank failed\n"));
    781     }
    782 
    783     present_execute(vblank, ust, crtc_msc);
    784 
    785     return Success;
    786 }
    787 
    788 static void
    789 present_scmd_abort_vblank(ScreenPtr screen, WindowPtr window, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
    790 {
    791     present_vblank_ptr  vblank;
    792 
    793     if (crtc == NULL)
    794         present_fake_abort_vblank(screen, event_id, msc);
    795     else
    796     {
    797         present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    798 
    799         (*screen_priv->info->abort_vblank) (crtc, event_id, msc);
    800     }
    801 
    802     xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) {
    803         int64_t match = event_id - vblank->event_id;
    804         if (match == 0) {
    805             xorg_list_del(&vblank->event_queue);
    806             vblank->queued = FALSE;
    807             return;
    808         }
    809     }
    810     xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
    811         if (vblank->event_id == event_id) {
    812             xorg_list_del(&vblank->event_queue);
    813             vblank->queued = FALSE;
    814             return;
    815         }
    816     }
    817 }
    818 
    819 static void
    820 present_scmd_flip_destroy(ScreenPtr screen)
    821 {
    822     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    823 
    824     /* Reset window pixmaps back to the screen pixmap */
    825     if (screen_priv->flip_pending)
    826         present_set_abort_flip(screen);
    827 
    828     /* Drop reference to any pending flip or unflip pixmaps. */
    829     present_flip_idle(screen);
    830 }
    831 
    832 void
    833 present_scmd_init_mode_hooks(present_screen_priv_ptr screen_priv)
    834 {
    835     screen_priv->query_capabilities =   &present_scmd_query_capabilities;
    836     screen_priv->get_crtc           =   &present_scmd_get_crtc;
    837 
    838     screen_priv->check_flip         =   &present_check_flip;
    839     screen_priv->check_flip_window  =   &present_check_flip_window;
    840     screen_priv->can_window_flip    =   &present_scmd_can_window_flip;
    841     screen_priv->clear_window_flip  =   &present_scmd_clear_window_flip;
    842 
    843     screen_priv->present_pixmap     =   &present_scmd_pixmap;
    844 
    845     screen_priv->queue_vblank       =   &present_queue_vblank;
    846     screen_priv->flush              =   &present_flush;
    847     screen_priv->re_execute         =   &present_re_execute;
    848 
    849     screen_priv->abort_vblank       =   &present_scmd_abort_vblank;
    850     screen_priv->flip_destroy       =   &present_scmd_flip_destroy;
    851 }
    852 
    853 Bool
    854 present_init(void)
    855 {
    856     xorg_list_init(&present_exec_queue);
    857     xorg_list_init(&present_flip_queue);
    858     present_fake_queue_init();
    859     return TRUE;
    860 }
    861