xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

present_scmd.c (28199B)


      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     return (*screen_priv->info->get_crtc)(window);
    162 }
    163 
    164 static uint32_t
    165 present_scmd_query_capabilities(present_screen_priv_ptr screen_priv)
    166 {
    167     if (!screen_priv->info)
    168         return 0;
    169 
    170     return screen_priv->info->capabilities;
    171 }
    172 
    173 static int
    174 present_get_ust_msc(ScreenPtr screen, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
    175 {
    176     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    177     present_screen_priv_ptr     crtc_screen_priv = screen_priv;
    178     if (crtc)
    179         crtc_screen_priv = present_screen_priv(crtc->pScreen);
    180 
    181     if (crtc == NULL)
    182         return present_fake_get_ust_msc(screen, ust, msc);
    183     else
    184         return (*crtc_screen_priv->info->get_ust_msc)(crtc, ust, msc);
    185 }
    186 
    187 static void
    188 present_flush(WindowPtr window)
    189 {
    190     ScreenPtr                   screen = window->drawable.pScreen;
    191     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    192 
    193     if (!screen_priv)
    194         return;
    195 
    196     if (!screen_priv->info)
    197         return;
    198 
    199     (*screen_priv->info->flush) (window);
    200 }
    201 
    202 static int
    203 present_queue_vblank(ScreenPtr screen,
    204                      WindowPtr window,
    205                      RRCrtcPtr crtc,
    206                      uint64_t event_id,
    207                      uint64_t msc)
    208 {
    209     Bool                        ret;
    210 
    211     if (crtc == NULL)
    212         ret = present_fake_queue_vblank(screen, event_id, msc);
    213     else
    214     {
    215         present_screen_priv_ptr     screen_priv = present_screen_priv(crtc->pScreen);
    216         ret = (*screen_priv->info->queue_vblank) (crtc, event_id, msc);
    217     }
    218     return ret;
    219 }
    220 
    221 /*
    222  * When the wait fence or previous flip is completed, it's time
    223  * to re-try the request
    224  */
    225 static void
    226 present_re_execute(present_vblank_ptr vblank)
    227 {
    228     uint64_t            ust = 0, crtc_msc = 0;
    229 
    230     if (vblank->crtc)
    231         (void) present_get_ust_msc(vblank->screen, vblank->crtc, &ust, &crtc_msc);
    232 
    233     present_execute(vblank, ust, crtc_msc);
    234 }
    235 
    236 static void
    237 present_flip_try_ready(ScreenPtr screen)
    238 {
    239     present_vblank_ptr  vblank;
    240 
    241     xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
    242         if (vblank->queued) {
    243             present_re_execute(vblank);
    244             return;
    245         }
    246     }
    247 }
    248 
    249 static void
    250 present_flip_idle(ScreenPtr screen)
    251 {
    252     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    253 
    254     if (screen_priv->flip_pixmap) {
    255         present_pixmap_idle(screen_priv->flip_pixmap, screen_priv->flip_window,
    256                             screen_priv->flip_serial, screen_priv->flip_idle_fence);
    257         if (screen_priv->flip_idle_fence)
    258             present_fence_destroy(screen_priv->flip_idle_fence);
    259         dixDestroyPixmap(screen_priv->flip_pixmap, screen_priv->flip_pixmap->drawable.id);
    260         screen_priv->flip_crtc = NULL;
    261         screen_priv->flip_window = NULL;
    262         screen_priv->flip_serial = 0;
    263         screen_priv->flip_pixmap = NULL;
    264         screen_priv->flip_idle_fence = NULL;
    265     }
    266 }
    267 
    268 void
    269 present_restore_screen_pixmap(ScreenPtr screen)
    270 {
    271     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    272     PixmapPtr screen_pixmap = (*screen->GetScreenPixmap)(screen);
    273     PixmapPtr flip_pixmap;
    274     WindowPtr flip_window;
    275 
    276     if (screen_priv->flip_pending) {
    277         flip_window = screen_priv->flip_pending->window;
    278         flip_pixmap = screen_priv->flip_pending->pixmap;
    279     } else {
    280         flip_window = screen_priv->flip_window;
    281         flip_pixmap = screen_priv->flip_pixmap;
    282     }
    283 
    284     assert (flip_pixmap);
    285 
    286     /* Update the screen pixmap with the current flip pixmap contents
    287      * Only do this the first time for a particular unflip operation, or
    288      * we'll probably scribble over other windows
    289      */
    290     if (screen->root && screen->GetWindowPixmap(screen->root) == flip_pixmap)
    291         present_copy_region(&screen_pixmap->drawable, flip_pixmap, NULL, 0, 0);
    292 
    293     /* Switch back to using the screen pixmap now to avoid
    294      * 2D applications drawing to the wrong pixmap.
    295      */
    296     if (flip_window)
    297         present_set_tree_pixmap(flip_window, flip_pixmap, screen_pixmap);
    298     if (screen->root)
    299         present_set_tree_pixmap(screen->root, NULL, screen_pixmap);
    300 }
    301 
    302 void
    303 present_set_abort_flip(ScreenPtr screen)
    304 {
    305     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    306 
    307     if (!screen_priv->flip_pending->abort_flip) {
    308         present_restore_screen_pixmap(screen);
    309         screen_priv->flip_pending->abort_flip = TRUE;
    310     }
    311 }
    312 
    313 static void
    314 present_unflip(ScreenPtr screen)
    315 {
    316     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    317 
    318     assert (!screen_priv->unflip_event_id);
    319     assert (!screen_priv->flip_pending);
    320 
    321     present_restore_screen_pixmap(screen);
    322 
    323     screen_priv->unflip_event_id = ++present_scmd_event_id;
    324     DebugPresent(("u %" PRIu64 "\n", screen_priv->unflip_event_id));
    325     (*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id);
    326 }
    327 
    328 static void
    329 present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
    330 {
    331     ScreenPtr                   screen = vblank->screen;
    332     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    333 
    334     DebugPresent(("\tn %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
    335                   vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc,
    336                   vblank->pixmap ? vblank->pixmap->drawable.id : 0,
    337                   vblank->window ? vblank->window->drawable.id : 0));
    338 
    339     assert (vblank == screen_priv->flip_pending);
    340 
    341     present_flip_idle(screen);
    342 
    343     xorg_list_del(&vblank->event_queue);
    344 
    345     /* Transfer reference for pixmap and fence from vblank to screen_priv */
    346     screen_priv->flip_crtc = vblank->crtc;
    347     screen_priv->flip_window = vblank->window;
    348     screen_priv->flip_serial = vblank->serial;
    349     screen_priv->flip_pixmap = vblank->pixmap;
    350     screen_priv->flip_sync = vblank->sync_flip;
    351     screen_priv->flip_idle_fence = vblank->idle_fence;
    352 
    353     vblank->pixmap = NULL;
    354     vblank->idle_fence = NULL;
    355 
    356     screen_priv->flip_pending = NULL;
    357 
    358     if (vblank->abort_flip)
    359         present_unflip(screen);
    360 
    361     present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
    362     present_vblank_destroy(vblank);
    363 
    364     present_flip_try_ready(screen);
    365 }
    366 
    367 void
    368 present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc)
    369 {
    370     present_vblank_ptr  vblank;
    371     int                 s;
    372 
    373     if (!event_id)
    374         return;
    375     DebugPresent(("\te %" PRIu64 " ust %" PRIu64 " msc %" PRIu64 "\n", event_id, ust, msc));
    376     xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) {
    377         int64_t match = event_id - vblank->event_id;
    378         if (match == 0) {
    379             present_execute(vblank, ust, msc);
    380             return;
    381         }
    382     }
    383     xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
    384         if (vblank->event_id == event_id) {
    385             if (vblank->queued)
    386                 present_execute(vblank, ust, msc);
    387             else
    388                 present_flip_notify(vblank, ust, msc);
    389             return;
    390         }
    391     }
    392 
    393     for (s = 0; s < screenInfo.numScreens; s++) {
    394         ScreenPtr               screen = screenInfo.screens[s];
    395         present_screen_priv_ptr screen_priv = present_screen_priv(screen);
    396 
    397         if (event_id == screen_priv->unflip_event_id) {
    398             DebugPresent(("\tun %" PRIu64 "\n", event_id));
    399             screen_priv->unflip_event_id = 0;
    400             present_flip_idle(screen);
    401             present_flip_try_ready(screen);
    402             return;
    403         }
    404     }
    405 }
    406 
    407 /*
    408  * 'window' is being reconfigured. Check to see if it is involved
    409  * in flipping and clean up as necessary
    410  */
    411 static void
    412 present_check_flip_window (WindowPtr window)
    413 {
    414     ScreenPtr                   screen = window->drawable.pScreen;
    415     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    416     present_window_priv_ptr     window_priv = present_window_priv(window);
    417     present_vblank_ptr          flip_pending = screen_priv->flip_pending;
    418     present_vblank_ptr          vblank;
    419     PresentFlipReason           reason;
    420 
    421     /* If this window hasn't ever been used with Present, it can't be
    422      * flipping
    423      */
    424     if (!window_priv)
    425         return;
    426 
    427     if (screen_priv->unflip_event_id)
    428         return;
    429 
    430     if (flip_pending) {
    431         /*
    432          * Check pending flip
    433          */
    434         if (flip_pending->window == window) {
    435             if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
    436                                     flip_pending->sync_flip, NULL, 0, 0, NULL))
    437                 present_set_abort_flip(screen);
    438         }
    439     } else {
    440         /*
    441          * Check current flip
    442          */
    443         if (window == screen_priv->flip_window) {
    444             if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0, NULL))
    445                 present_unflip(screen);
    446         }
    447     }
    448 
    449     /* Now check any queued vblanks */
    450     xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
    451         if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) {
    452             vblank->flip = FALSE;
    453             vblank->reason = reason;
    454             if (vblank->sync_flip)
    455                 vblank->exec_msc = vblank->target_msc;
    456         }
    457     }
    458 }
    459 
    460 static Bool
    461 present_scmd_can_window_flip(WindowPtr window)
    462 {
    463     ScreenPtr                   screen = window->drawable.pScreen;
    464     PixmapPtr                   window_pixmap;
    465     WindowPtr                   root = screen->root;
    466     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    467 
    468     if (!screen_priv)
    469         return FALSE;
    470 
    471     if (!screen_priv->info)
    472         return FALSE;
    473 
    474     /* Check to see if the driver supports flips at all */
    475     if (!screen_priv->info->flip)
    476         return FALSE;
    477 
    478     /* Make sure the window hasn't been redirected with Composite */
    479     window_pixmap = screen->GetWindowPixmap(window);
    480     if (window_pixmap != screen->GetScreenPixmap(screen) &&
    481         window_pixmap != screen_priv->flip_pixmap &&
    482         window_pixmap != present_flip_pending_pixmap(screen))
    483         return FALSE;
    484 
    485     /* Check for full-screen window */
    486     if (!RegionEqual(&window->clipList, &root->winSize)) {
    487         return FALSE;
    488     }
    489 
    490     /* Does the window match the pixmap exactly? */
    491     if (window->drawable.x != 0 || window->drawable.y != 0) {
    492         return FALSE;
    493     }
    494 
    495     return TRUE;
    496 }
    497 
    498 /*
    499  * Clean up any pending or current flips for this window
    500  */
    501 static void
    502 present_scmd_clear_window_flip(WindowPtr window)
    503 {
    504     ScreenPtr                   screen = window->drawable.pScreen;
    505     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    506     present_vblank_ptr          flip_pending = screen_priv->flip_pending;
    507 
    508     if (flip_pending && flip_pending->window == window) {
    509         present_set_abort_flip(screen);
    510         flip_pending->window = NULL;
    511     }
    512     if (screen_priv->flip_window == window) {
    513         present_restore_screen_pixmap(screen);
    514         screen_priv->flip_window = NULL;
    515     }
    516 }
    517 
    518 /*
    519  * Once the required MSC has been reached, execute the pending request.
    520  *
    521  * For requests to actually present something, either blt contents to
    522  * the screen or queue a frame buffer swap.
    523  *
    524  * For requests to just get the current MSC/UST combo, skip that part and
    525  * go straight to event delivery
    526  */
    527 
    528 static void
    529 present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
    530 {
    531     WindowPtr                   window = vblank->window;
    532     ScreenPtr                   screen = window->drawable.pScreen;
    533     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    534     if (vblank && vblank->crtc) {
    535         screen_priv=present_screen_priv(vblank->crtc->pScreen);
    536     }
    537 
    538     if (present_execute_wait(vblank, crtc_msc))
    539         return;
    540 
    541     if (vblank->flip && vblank->pixmap && vblank->window) {
    542         if (screen_priv->flip_pending || screen_priv->unflip_event_id) {
    543             DebugPresent(("\tr %" PRIu64 " %p (pending %p unflip %" PRIu64 ")\n",
    544                           vblank->event_id, vblank,
    545                           screen_priv->flip_pending, screen_priv->unflip_event_id));
    546             xorg_list_del(&vblank->event_queue);
    547             xorg_list_append(&vblank->event_queue, &present_flip_queue);
    548             vblank->flip_ready = TRUE;
    549             return;
    550         }
    551     }
    552 
    553     xorg_list_del(&vblank->event_queue);
    554     xorg_list_del(&vblank->window_list);
    555     vblank->queued = FALSE;
    556 
    557     if (vblank->pixmap && vblank->window) {
    558 
    559         if (vblank->flip) {
    560 
    561             DebugPresent(("\tf %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
    562                           vblank->event_id, vblank, crtc_msc,
    563                           vblank->pixmap->drawable.id, vblank->window->drawable.id));
    564 
    565             /* Prepare to flip by placing it in the flip queue and
    566              * and sticking it into the flip_pending field
    567              */
    568             screen_priv->flip_pending = vblank;
    569 
    570             xorg_list_add(&vblank->event_queue, &present_flip_queue);
    571             /* Try to flip
    572              */
    573             if (present_flip(vblank->crtc, vblank->event_id, vblank->target_msc, vblank->pixmap, vblank->sync_flip)) {
    574                 RegionPtr damage;
    575 
    576                 /* Fix window pixmaps:
    577                  *  1) Restore previous flip window pixmap
    578                  *  2) Set current flip window pixmap to the new pixmap
    579                  */
    580                 if (screen_priv->flip_window && screen_priv->flip_window != window)
    581                     present_set_tree_pixmap(screen_priv->flip_window,
    582                                             screen_priv->flip_pixmap,
    583                                             (*screen->GetScreenPixmap)(screen));
    584                 present_set_tree_pixmap(vblank->window, NULL, vblank->pixmap);
    585                 present_set_tree_pixmap(screen->root, NULL, vblank->pixmap);
    586 
    587                 /* Report update region as damaged
    588                  */
    589                 if (vblank->update) {
    590                     damage = vblank->update;
    591                     RegionIntersect(damage, damage, &window->clipList);
    592                 } else
    593                     damage = &window->clipList;
    594 
    595                 DamageDamageRegion(&vblank->window->drawable, damage);
    596                 return;
    597             }
    598 
    599             xorg_list_del(&vblank->event_queue);
    600             /* Oops, flip failed. Clear the flip_pending field
    601               */
    602             screen_priv->flip_pending = NULL;
    603             vblank->flip = FALSE;
    604             vblank->exec_msc = vblank->target_msc;
    605         }
    606         DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
    607                       vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
    608         if (screen_priv->flip_pending) {
    609 
    610             /* Check pending flip
    611              */
    612             if (window == screen_priv->flip_pending->window)
    613                 present_set_abort_flip(screen);
    614         } else if (!screen_priv->unflip_event_id) {
    615 
    616             /* Check current flip
    617              */
    618             if (window == screen_priv->flip_window)
    619                 present_unflip(screen);
    620         }
    621 
    622         present_execute_copy(vblank, crtc_msc);
    623 
    624         if (vblank->queued) {
    625             xorg_list_add(&vblank->event_queue, &present_exec_queue);
    626             xorg_list_append(&vblank->window_list,
    627                              &present_get_window_priv(window, TRUE)->vblank);
    628             return;
    629         }
    630     }
    631 
    632     present_execute_post(vblank, ust, crtc_msc);
    633 }
    634 
    635 static void
    636 present_scmd_update_window_crtc(WindowPtr window, RRCrtcPtr crtc, uint64_t new_msc)
    637 {
    638     present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
    639     uint64_t                old_ust, old_msc;
    640 
    641     /* Crtc unchanged, no offset. */
    642     if (crtc == window_priv->crtc)
    643         return;
    644 
    645     /* No crtc earlier to offset against, just set the crtc. */
    646     if (window_priv->crtc == PresentCrtcNeverSet) {
    647         window_priv->crtc = crtc;
    648         return;
    649     }
    650 
    651     /* Crtc may have been turned off or be destroyed, just use whatever previous MSC we'd seen from this CRTC. */
    652     if (!RRCrtcExists(window->drawable.pScreen, window_priv->crtc) ||
    653         present_get_ust_msc(window->drawable.pScreen, window_priv->crtc, &old_ust, &old_msc) != Success)
    654         old_msc = window_priv->msc;
    655 
    656     window_priv->msc_offset += new_msc - old_msc;
    657     window_priv->crtc = crtc;
    658 }
    659 
    660 static int
    661 present_scmd_pixmap(WindowPtr window,
    662                     PixmapPtr pixmap,
    663                     CARD32 serial,
    664                     RegionPtr valid,
    665                     RegionPtr update,
    666                     int16_t x_off,
    667                     int16_t y_off,
    668                     RRCrtcPtr target_crtc,
    669                     SyncFence *wait_fence,
    670                     SyncFence *idle_fence,
    671                     uint32_t options,
    672                     uint64_t target_window_msc,
    673                     uint64_t divisor,
    674                     uint64_t remainder,
    675                     present_notify_ptr notifies,
    676                     int num_notifies)
    677 {
    678     uint64_t                    ust = 0;
    679     uint64_t                    target_msc;
    680     uint64_t                    crtc_msc = 0;
    681     int                         ret;
    682     present_vblank_ptr          vblank, tmp;
    683     ScreenPtr                   screen = window->drawable.pScreen;
    684     present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
    685     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    686 
    687     if (!window_priv)
    688         return BadAlloc;
    689 
    690     if (!screen_priv || !screen_priv->info)
    691         target_crtc = NULL;
    692     else if (!target_crtc) {
    693         /* Update the CRTC if we have a pixmap or we don't have a CRTC
    694          */
    695         if (!pixmap)
    696             target_crtc = window_priv->crtc;
    697 
    698         if (!target_crtc || target_crtc == PresentCrtcNeverSet)
    699             target_crtc = present_get_crtc(window);
    700     }
    701 
    702     ret = present_get_ust_msc(screen, target_crtc, &ust, &crtc_msc);
    703 
    704     present_scmd_update_window_crtc(window, target_crtc, crtc_msc);
    705 
    706     if (ret == Success) {
    707         /* Stash the current MSC away in case we need it later
    708          */
    709         window_priv->msc = crtc_msc;
    710     }
    711 
    712     target_msc = present_get_target_msc(target_window_msc + window_priv->msc_offset,
    713                                         crtc_msc,
    714                                         divisor,
    715                                         remainder,
    716                                         options);
    717 
    718     /*
    719      * Look for a matching presentation already on the list and
    720      * don't bother doing the previous one if this one will overwrite it
    721      * in the same frame
    722      */
    723 
    724     if (!update && pixmap) {
    725         xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
    726 
    727             if (!vblank->pixmap)
    728                 continue;
    729 
    730             if (!vblank->queued)
    731                 continue;
    732 
    733             if (vblank->crtc != target_crtc || vblank->target_msc != target_msc)
    734                 continue;
    735 
    736             present_vblank_scrap(vblank);
    737             if (vblank->flip_ready)
    738                 present_re_execute(vblank);
    739         }
    740     }
    741 
    742     vblank = present_vblank_create(window,
    743                                    pixmap,
    744                                    serial,
    745                                    valid,
    746                                    update,
    747                                    x_off,
    748                                    y_off,
    749                                    target_crtc,
    750                                    wait_fence,
    751                                    idle_fence,
    752                                    options,
    753                                    screen_priv->info ? screen_priv->info->capabilities : 0,
    754                                    notifies,
    755                                    num_notifies,
    756                                    target_msc,
    757                                    crtc_msc);
    758 
    759     if (!vblank)
    760         return BadAlloc;
    761 
    762     vblank->event_id = ++present_scmd_event_id;
    763 
    764     if (vblank->flip && vblank->sync_flip)
    765         vblank->exec_msc--;
    766 
    767     xorg_list_append(&vblank->event_queue, &present_exec_queue);
    768     vblank->queued = TRUE;
    769     if (msc_is_after(vblank->exec_msc, crtc_msc)) {
    770         ret = present_queue_vblank(screen, window, target_crtc, vblank->event_id, vblank->exec_msc);
    771         if (ret == Success)
    772             return Success;
    773 
    774         DebugPresent(("present_queue_vblank failed\n"));
    775     }
    776 
    777     present_execute(vblank, ust, crtc_msc);
    778 
    779     return Success;
    780 }
    781 
    782 static void
    783 present_scmd_abort_vblank(ScreenPtr screen, WindowPtr window, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
    784 {
    785     present_vblank_ptr  vblank;
    786 
    787     if (crtc == NULL)
    788         present_fake_abort_vblank(screen, event_id, msc);
    789     else
    790     {
    791         present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    792 
    793         (*screen_priv->info->abort_vblank) (crtc, event_id, msc);
    794     }
    795 
    796     xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) {
    797         int64_t match = event_id - vblank->event_id;
    798         if (match == 0) {
    799             xorg_list_del(&vblank->event_queue);
    800             vblank->queued = FALSE;
    801             return;
    802         }
    803     }
    804     xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) {
    805         if (vblank->event_id == event_id) {
    806             xorg_list_del(&vblank->event_queue);
    807             vblank->queued = FALSE;
    808             return;
    809         }
    810     }
    811 }
    812 
    813 static void
    814 present_scmd_flip_destroy(ScreenPtr screen)
    815 {
    816     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
    817 
    818     /* Reset window pixmaps back to the screen pixmap */
    819     if (screen_priv->flip_pending)
    820         present_set_abort_flip(screen);
    821 
    822     /* Drop reference to any pending flip or unflip pixmaps. */
    823     present_flip_idle(screen);
    824 }
    825 
    826 void
    827 present_scmd_init_mode_hooks(present_screen_priv_ptr screen_priv)
    828 {
    829     screen_priv->query_capabilities =   &present_scmd_query_capabilities;
    830     screen_priv->get_crtc           =   &present_scmd_get_crtc;
    831 
    832     screen_priv->check_flip         =   &present_check_flip;
    833     screen_priv->check_flip_window  =   &present_check_flip_window;
    834     screen_priv->can_window_flip    =   &present_scmd_can_window_flip;
    835     screen_priv->clear_window_flip  =   &present_scmd_clear_window_flip;
    836 
    837     screen_priv->present_pixmap     =   &present_scmd_pixmap;
    838 
    839     screen_priv->queue_vblank       =   &present_queue_vblank;
    840     screen_priv->flush              =   &present_flush;
    841     screen_priv->re_execute         =   &present_re_execute;
    842 
    843     screen_priv->abort_vblank       =   &present_scmd_abort_vblank;
    844     screen_priv->flip_destroy       =   &present_scmd_flip_destroy;
    845 }
    846 
    847 Bool
    848 present_init(void)
    849 {
    850     xorg_list_init(&present_exec_queue);
    851     xorg_list_init(&present_flip_queue);
    852     present_fake_queue_init();
    853     return TRUE;
    854 }