xserver

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

dri2.c (33303B)


      1 /*
      2  * Copyright © 2013 Intel Corporation
      3  * Copyright © 2014 Broadcom
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     22  * IN THE SOFTWARE.
     23  */
     24 
     25 /**
     26  * @file dri2.c
     27  *
     28  * Implements generic support for DRI2 on KMS, using glamor pixmaps
     29  * for color buffer management (no support for other aux buffers), and
     30  * the DRM vblank ioctls.
     31  *
     32  * This doesn't implement pageflipping yet.
     33  */
     34 
     35 #ifdef HAVE_DIX_CONFIG_H
     36 #include "dix-config.h"
     37 #endif
     38 
     39 #include <time.h>
     40 #include "list.h"
     41 #include "xf86.h"
     42 #include "driver.h"
     43 #include "dri2.h"
     44 
     45 #ifdef GLAMOR_HAS_GBM
     46 
     47 enum ms_dri2_frame_event_type {
     48     MS_DRI2_QUEUE_SWAP,
     49     MS_DRI2_QUEUE_FLIP,
     50     MS_DRI2_WAIT_MSC,
     51 };
     52 
     53 typedef struct ms_dri2_frame_event {
     54     ScreenPtr screen;
     55 
     56     DrawablePtr drawable;
     57     ClientPtr client;
     58     enum ms_dri2_frame_event_type type;
     59     int frame;
     60     xf86CrtcPtr crtc;
     61 
     62     struct xorg_list drawable_resource, client_resource;
     63 
     64     /* for swaps & flips only */
     65     DRI2SwapEventPtr event_complete;
     66     void *event_data;
     67     DRI2BufferPtr front;
     68     DRI2BufferPtr back;
     69 } ms_dri2_frame_event_rec, *ms_dri2_frame_event_ptr;
     70 
     71 typedef struct {
     72     int refcnt;
     73     PixmapPtr pixmap;
     74 } ms_dri2_buffer_private_rec, *ms_dri2_buffer_private_ptr;
     75 
     76 static DevPrivateKeyRec ms_dri2_client_key;
     77 static RESTYPE frame_event_client_type, frame_event_drawable_type;
     78 static int ms_dri2_server_generation;
     79 
     80 struct ms_dri2_resource {
     81     XID id;
     82     RESTYPE type;
     83     struct xorg_list list;
     84 };
     85 
     86 static struct ms_dri2_resource *
     87 ms_get_resource(XID id, RESTYPE type)
     88 {
     89     struct ms_dri2_resource *resource;
     90     void *ptr;
     91 
     92     ptr = NULL;
     93     dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess);
     94     if (ptr)
     95         return ptr;
     96 
     97     resource = malloc(sizeof(*resource));
     98     if (resource == NULL)
     99         return NULL;
    100 
    101     if (!AddResource(id, type, resource))
    102         return NULL;
    103 
    104     resource->id = id;
    105     resource->type = type;
    106     xorg_list_init(&resource->list);
    107     return resource;
    108 }
    109 
    110 static inline PixmapPtr
    111 get_drawable_pixmap(DrawablePtr drawable)
    112 {
    113     ScreenPtr screen = drawable->pScreen;
    114 
    115     if (drawable->type == DRAWABLE_PIXMAP)
    116         return (PixmapPtr) drawable;
    117     else
    118         return screen->GetWindowPixmap((WindowPtr) drawable);
    119 }
    120 
    121 static DRI2Buffer2Ptr
    122 ms_dri2_create_buffer2(ScreenPtr screen, DrawablePtr drawable,
    123                        unsigned int attachment, unsigned int format)
    124 {
    125     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    126     modesettingPtr ms = modesettingPTR(scrn);
    127     DRI2Buffer2Ptr buffer;
    128     PixmapPtr pixmap;
    129     CARD32 size;
    130     CARD16 pitch;
    131     ms_dri2_buffer_private_ptr private;
    132 
    133     buffer = calloc(1, sizeof *buffer);
    134     if (buffer == NULL)
    135         return NULL;
    136 
    137     private = calloc(1, sizeof(*private));
    138     if (private == NULL) {
    139         free(buffer);
    140         return NULL;
    141     }
    142 
    143     pixmap = NULL;
    144     if (attachment == DRI2BufferFrontLeft) {
    145         pixmap = get_drawable_pixmap(drawable);
    146         if (pixmap && pixmap->drawable.pScreen != screen)
    147             pixmap = NULL;
    148         if (pixmap)
    149             pixmap->refcnt++;
    150     }
    151 
    152     if (pixmap == NULL) {
    153         int pixmap_width = drawable->width;
    154         int pixmap_height = drawable->height;
    155         int pixmap_cpp = (format != 0) ? format : drawable->depth;
    156 
    157         /* Assume that non-color-buffers require special
    158          * device-specific handling.  Mesa currently makes no requests
    159          * for non-color aux buffers.
    160          */
    161         switch (attachment) {
    162         case DRI2BufferAccum:
    163         case DRI2BufferBackLeft:
    164         case DRI2BufferBackRight:
    165         case DRI2BufferFakeFrontLeft:
    166         case DRI2BufferFakeFrontRight:
    167         case DRI2BufferFrontLeft:
    168         case DRI2BufferFrontRight:
    169             break;
    170 
    171         case DRI2BufferStencil:
    172         case DRI2BufferDepth:
    173         case DRI2BufferDepthStencil:
    174         case DRI2BufferHiz:
    175         default:
    176             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
    177                        "Request for DRI2 buffer attachment %d unsupported\n",
    178                        attachment);
    179             free(private);
    180             free(buffer);
    181             return NULL;
    182         }
    183 
    184         pixmap = screen->CreatePixmap(screen,
    185                                       pixmap_width,
    186                                       pixmap_height,
    187                                       pixmap_cpp,
    188                                       0);
    189         if (pixmap == NULL) {
    190             free(private);
    191             free(buffer);
    192             return NULL;
    193         }
    194     }
    195 
    196     buffer->attachment = attachment;
    197     buffer->cpp = pixmap->drawable.bitsPerPixel / 8;
    198     buffer->format = format;
    199     /* The buffer's flags field is unused by the client drivers in
    200      * Mesa currently.
    201      */
    202     buffer->flags = 0;
    203 
    204     buffer->name = ms->glamor.name_from_pixmap(pixmap, &pitch, &size);
    205     buffer->pitch = pitch;
    206     if (buffer->name == -1) {
    207         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    208                    "Failed to get DRI2 name for pixmap\n");
    209         screen->DestroyPixmap(pixmap);
    210         free(private);
    211         free(buffer);
    212         return NULL;
    213     }
    214 
    215     buffer->driverPrivate = private;
    216     private->refcnt = 1;
    217     private->pixmap = pixmap;
    218 
    219     return buffer;
    220 }
    221 
    222 static DRI2Buffer2Ptr
    223 ms_dri2_create_buffer(DrawablePtr drawable, unsigned int attachment,
    224                       unsigned int format)
    225 {
    226     return ms_dri2_create_buffer2(drawable->pScreen, drawable, attachment,
    227                                   format);
    228 }
    229 
    230 static void
    231 ms_dri2_reference_buffer(DRI2Buffer2Ptr buffer)
    232 {
    233     if (buffer) {
    234         ms_dri2_buffer_private_ptr private = buffer->driverPrivate;
    235         private->refcnt++;
    236     }
    237 }
    238 
    239 static void ms_dri2_destroy_buffer2(ScreenPtr unused, DrawablePtr unused2,
    240                                     DRI2Buffer2Ptr buffer)
    241 {
    242     if (!buffer)
    243         return;
    244 
    245     if (buffer->driverPrivate) {
    246         ms_dri2_buffer_private_ptr private = buffer->driverPrivate;
    247         if (--private->refcnt == 0) {
    248             ScreenPtr screen = private->pixmap->drawable.pScreen;
    249             screen->DestroyPixmap(private->pixmap);
    250             free(private);
    251             free(buffer);
    252         }
    253     } else {
    254         free(buffer);
    255     }
    256 }
    257 
    258 static void ms_dri2_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
    259 {
    260     ms_dri2_destroy_buffer2(NULL, drawable, buffer);
    261 }
    262 
    263 static void
    264 ms_dri2_copy_region2(ScreenPtr screen, DrawablePtr drawable, RegionPtr pRegion,
    265                      DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
    266 {
    267     ms_dri2_buffer_private_ptr src_priv = sourceBuffer->driverPrivate;
    268     ms_dri2_buffer_private_ptr dst_priv = destBuffer->driverPrivate;
    269     PixmapPtr src_pixmap = src_priv->pixmap;
    270     PixmapPtr dst_pixmap = dst_priv->pixmap;
    271     DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft)
    272         ? drawable : &src_pixmap->drawable;
    273     DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft)
    274         ? drawable : &dst_pixmap->drawable;
    275     int off_x = 0, off_y = 0;
    276     Bool translate = FALSE;
    277     RegionPtr pCopyClip;
    278     GCPtr gc;
    279 
    280     if (destBuffer->attachment == DRI2BufferFrontLeft &&
    281              drawable->pScreen != screen) {
    282         dst = DRI2UpdatePrime(drawable, destBuffer);
    283         if (!dst)
    284             return;
    285         if (dst != drawable)
    286             translate = TRUE;
    287     }
    288 
    289     if (translate && drawable->type == DRAWABLE_WINDOW) {
    290 #ifdef COMPOSITE
    291         PixmapPtr pixmap = get_drawable_pixmap(drawable);
    292         off_x = -pixmap->screen_x;
    293         off_y = -pixmap->screen_y;
    294 #endif
    295         off_x += drawable->x;
    296         off_y += drawable->y;
    297     }
    298 
    299     gc = GetScratchGC(dst->depth, screen);
    300     if (!gc)
    301         return;
    302 
    303     pCopyClip = REGION_CREATE(screen, NULL, 0);
    304     REGION_COPY(screen, pCopyClip, pRegion);
    305     if (translate)
    306         REGION_TRANSLATE(screen, pCopyClip, off_x, off_y);
    307     (*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0);
    308     ValidateGC(dst, gc);
    309 
    310     /* It's important that this copy gets submitted before the direct
    311      * rendering client submits rendering for the next frame, but we
    312      * don't actually need to submit right now.  The client will wait
    313      * for the DRI2CopyRegion reply or the swap buffer event before
    314      * rendering, and we'll hit the flush callback chain before those
    315      * messages are sent.  We submit our batch buffers from the flush
    316      * callback chain so we know that will happen before the client
    317      * tries to render again.
    318      */
    319     gc->ops->CopyArea(src, dst, gc,
    320                       0, 0,
    321                       drawable->width, drawable->height,
    322                       off_x, off_y);
    323 
    324     FreeScratchGC(gc);
    325 }
    326 
    327 static void
    328 ms_dri2_copy_region(DrawablePtr drawable, RegionPtr pRegion,
    329                     DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
    330 {
    331     ms_dri2_copy_region2(drawable->pScreen, drawable, pRegion, destBuffer,
    332                          sourceBuffer);
    333 }
    334 
    335 static uint64_t
    336 gettime_us(void)
    337 {
    338     struct timespec tv;
    339 
    340     if (clock_gettime(CLOCK_MONOTONIC, &tv))
    341         return 0;
    342 
    343     return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
    344 }
    345 
    346 /**
    347  * Get current frame count and frame count timestamp, based on drawable's
    348  * crtc.
    349  */
    350 static int
    351 ms_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
    352 {
    353     int ret;
    354     xf86CrtcPtr crtc = ms_dri2_crtc_covering_drawable(draw);
    355 
    356     /* Drawable not displayed, make up a *monotonic* value */
    357     if (crtc == NULL) {
    358         *ust = gettime_us();
    359         *msc = 0;
    360         return TRUE;
    361     }
    362 
    363     ret = ms_get_crtc_ust_msc(crtc, ust, msc);
    364 
    365     if (ret)
    366         return FALSE;
    367 
    368     return TRUE;
    369 }
    370 
    371 static XID
    372 get_client_id(ClientPtr client)
    373 {
    374     XID *ptr = dixGetPrivateAddr(&client->devPrivates, &ms_dri2_client_key);
    375     if (*ptr == 0)
    376         *ptr = FakeClientID(client->index);
    377     return *ptr;
    378 }
    379 
    380 /*
    381  * Hook this frame event into the server resource
    382  * database so we can clean it up if the drawable or
    383  * client exits while the swap is pending
    384  */
    385 static Bool
    386 ms_dri2_add_frame_event(ms_dri2_frame_event_ptr info)
    387 {
    388     struct ms_dri2_resource *resource;
    389 
    390     resource = ms_get_resource(get_client_id(info->client),
    391                                frame_event_client_type);
    392     if (resource == NULL)
    393         return FALSE;
    394 
    395     xorg_list_add(&info->client_resource, &resource->list);
    396 
    397     resource = ms_get_resource(info->drawable->id, frame_event_drawable_type);
    398     if (resource == NULL) {
    399         xorg_list_del(&info->client_resource);
    400         return FALSE;
    401     }
    402 
    403     xorg_list_add(&info->drawable_resource, &resource->list);
    404 
    405     return TRUE;
    406 }
    407 
    408 static void
    409 ms_dri2_del_frame_event(ms_dri2_frame_event_rec *info)
    410 {
    411     xorg_list_del(&info->client_resource);
    412     xorg_list_del(&info->drawable_resource);
    413 
    414     if (info->front)
    415         ms_dri2_destroy_buffer(NULL, info->front);
    416     if (info->back)
    417         ms_dri2_destroy_buffer(NULL, info->back);
    418 
    419     free(info);
    420 }
    421 
    422 static void
    423 ms_dri2_blit_swap(DrawablePtr drawable,
    424                   DRI2BufferPtr dst,
    425                   DRI2BufferPtr src)
    426 {
    427     BoxRec box;
    428     RegionRec region;
    429 
    430     box.x1 = 0;
    431     box.y1 = 0;
    432     box.x2 = drawable->width;
    433     box.y2 = drawable->height;
    434     REGION_INIT(pScreen, &region, &box, 0);
    435 
    436     ms_dri2_copy_region(drawable, &region, dst, src);
    437 }
    438 
    439 struct ms_dri2_vblank_event {
    440     XID drawable_id;
    441     ClientPtr client;
    442     DRI2SwapEventPtr event_complete;
    443     void *event_data;
    444 };
    445 
    446 static void
    447 ms_dri2_flip_abort(modesettingPtr ms, void *data)
    448 {
    449     struct ms_present_vblank_event *event = data;
    450 
    451     ms->drmmode.dri2_flipping = FALSE;
    452     free(event);
    453 }
    454 
    455 static void
    456 ms_dri2_flip_handler(modesettingPtr ms, uint64_t msc,
    457                      uint64_t ust, void *data)
    458 {
    459     struct ms_dri2_vblank_event *event = data;
    460     uint32_t frame = msc;
    461     uint32_t tv_sec = ust / 1000000;
    462     uint32_t tv_usec = ust % 1000000;
    463     DrawablePtr drawable;
    464     int status;
    465 
    466     status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
    467                                M_ANY, DixWriteAccess);
    468     if (status == Success)
    469         DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec,
    470                          DRI2_FLIP_COMPLETE, event->event_complete,
    471                          event->event_data);
    472 
    473     ms->drmmode.dri2_flipping = FALSE;
    474     free(event);
    475 }
    476 
    477 static Bool
    478 ms_dri2_schedule_flip(ms_dri2_frame_event_ptr info)
    479 {
    480     DrawablePtr draw = info->drawable;
    481     ScreenPtr screen = draw->pScreen;
    482     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    483     modesettingPtr ms = modesettingPTR(scrn);
    484     ms_dri2_buffer_private_ptr back_priv = info->back->driverPrivate;
    485     struct ms_dri2_vblank_event *event;
    486     drmmode_crtc_private_ptr drmmode_crtc = info->crtc->driver_private;
    487 
    488     event = calloc(1, sizeof(struct ms_dri2_vblank_event));
    489     if (!event)
    490         return FALSE;
    491 
    492     event->drawable_id = draw->id;
    493     event->client = info->client;
    494     event->event_complete = info->event_complete;
    495     event->event_data = info->event_data;
    496 
    497     if (ms_do_pageflip(screen, back_priv->pixmap, event,
    498                        drmmode_crtc->vblank_pipe, FALSE,
    499                        ms_dri2_flip_handler,
    500                        ms_dri2_flip_abort,
    501                        "DRI2-flip")) {
    502         ms->drmmode.dri2_flipping = TRUE;
    503         return TRUE;
    504     }
    505     return FALSE;
    506 }
    507 
    508 static Bool
    509 update_front(DrawablePtr draw, DRI2BufferPtr front)
    510 {
    511     ScreenPtr screen = draw->pScreen;
    512     PixmapPtr pixmap = get_drawable_pixmap(draw);
    513     ms_dri2_buffer_private_ptr priv = front->driverPrivate;
    514     modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(screen));
    515     CARD32 size;
    516     CARD16 pitch;
    517     int name;
    518 
    519     name = ms->glamor.name_from_pixmap(pixmap, &pitch, &size);
    520     if (name < 0)
    521         return FALSE;
    522 
    523     front->name = name;
    524 
    525     (*screen->DestroyPixmap) (priv->pixmap);
    526     front->pitch = pixmap->devKind;
    527     front->cpp = pixmap->drawable.bitsPerPixel / 8;
    528     priv->pixmap = pixmap;
    529     pixmap->refcnt++;
    530 
    531     return TRUE;
    532 }
    533 
    534 static Bool
    535 can_exchange(ScrnInfoPtr scrn, DrawablePtr draw,
    536 	     DRI2BufferPtr front, DRI2BufferPtr back)
    537 {
    538     ms_dri2_buffer_private_ptr front_priv = front->driverPrivate;
    539     ms_dri2_buffer_private_ptr back_priv = back->driverPrivate;
    540     PixmapPtr front_pixmap;
    541     PixmapPtr back_pixmap = back_priv->pixmap;
    542     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
    543     int num_crtcs_on = 0;
    544     int i;
    545 
    546     for (i = 0; i < config->num_crtc; i++) {
    547         drmmode_crtc_private_ptr drmmode_crtc = config->crtc[i]->driver_private;
    548 
    549         /* Don't do pageflipping if CRTCs are rotated. */
    550 #ifdef GLAMOR_HAS_GBM
    551         if (drmmode_crtc->rotate_bo.gbm)
    552             return FALSE;
    553 #endif
    554 
    555         if (xf86_crtc_on(config->crtc[i]))
    556             num_crtcs_on++;
    557     }
    558 
    559     /* We can't do pageflipping if all the CRTCs are off. */
    560     if (num_crtcs_on == 0)
    561         return FALSE;
    562 
    563     if (!update_front(draw, front))
    564         return FALSE;
    565 
    566     front_pixmap = front_priv->pixmap;
    567 
    568     if (front_pixmap->drawable.width != back_pixmap->drawable.width)
    569         return FALSE;
    570 
    571     if (front_pixmap->drawable.height != back_pixmap->drawable.height)
    572         return FALSE;
    573 
    574     if (front_pixmap->drawable.bitsPerPixel !=
    575         back_pixmap->drawable.bitsPerPixel)
    576         return FALSE;
    577 
    578     if (front_pixmap->devKind != back_pixmap->devKind)
    579         return FALSE;
    580 
    581     return TRUE;
    582 }
    583 
    584 static Bool
    585 can_flip(ScrnInfoPtr scrn, DrawablePtr draw,
    586 	 DRI2BufferPtr front, DRI2BufferPtr back)
    587 {
    588     modesettingPtr ms = modesettingPTR(scrn);
    589 
    590     return draw->type == DRAWABLE_WINDOW &&
    591         ms->drmmode.pageflip &&
    592         !ms->drmmode.sprites_visible &&
    593         !ms->drmmode.present_flipping &&
    594         scrn->vtSema &&
    595         DRI2CanFlip(draw) && can_exchange(scrn, draw, front, back);
    596 }
    597 
    598 static void
    599 ms_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front,
    600                          DRI2BufferPtr back)
    601 {
    602     ms_dri2_buffer_private_ptr front_priv = front->driverPrivate;
    603     ms_dri2_buffer_private_ptr back_priv = back->driverPrivate;
    604     ScreenPtr screen = draw->pScreen;
    605     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    606     modesettingPtr ms = modesettingPTR(scrn);
    607     msPixmapPrivPtr front_pix = msGetPixmapPriv(&ms->drmmode, front_priv->pixmap);
    608     msPixmapPrivPtr back_pix = msGetPixmapPriv(&ms->drmmode, back_priv->pixmap);
    609     msPixmapPrivRec tmp_pix;
    610     RegionRec region;
    611     int tmp;
    612 
    613     /* Swap BO names so DRI works */
    614     tmp = front->name;
    615     front->name = back->name;
    616     back->name = tmp;
    617 
    618     /* Swap pixmap privates */
    619     tmp_pix = *front_pix;
    620     *front_pix = *back_pix;
    621     *back_pix = tmp_pix;
    622 
    623     ms->glamor.egl_exchange_buffers(front_priv->pixmap, back_priv->pixmap);
    624 
    625     /* Post damage on the front buffer so that listeners, such
    626      * as DisplayLink know take a copy and shove it over the USB.
    627      */
    628     region.extents.x1 = region.extents.y1 = 0;
    629     region.extents.x2 = front_priv->pixmap->drawable.width;
    630     region.extents.y2 = front_priv->pixmap->drawable.height;
    631     region.data = NULL;
    632     DamageRegionAppend(&front_priv->pixmap->drawable, &region);
    633     DamageRegionProcessPending(&front_priv->pixmap->drawable);
    634 }
    635 
    636 static void
    637 ms_dri2_frame_event_handler(uint64_t msc,
    638                             uint64_t usec,
    639                             void *data)
    640 {
    641     ms_dri2_frame_event_ptr frame_info = data;
    642     DrawablePtr drawable = frame_info->drawable;
    643     ScreenPtr screen = frame_info->screen;
    644     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    645     uint32_t tv_sec = usec / 1000000;
    646     uint32_t tv_usec = usec % 1000000;
    647 
    648     if (!drawable) {
    649         ms_dri2_del_frame_event(frame_info);
    650         return;
    651     }
    652 
    653     switch (frame_info->type) {
    654     case MS_DRI2_QUEUE_FLIP:
    655         if (can_flip(scrn, drawable, frame_info->front, frame_info->back) &&
    656             ms_dri2_schedule_flip(frame_info)) {
    657             ms_dri2_exchange_buffers(drawable, frame_info->front, frame_info->back);
    658             break;
    659         }
    660         /* else fall through to blit */
    661     case MS_DRI2_QUEUE_SWAP:
    662         ms_dri2_blit_swap(drawable, frame_info->front, frame_info->back);
    663         DRI2SwapComplete(frame_info->client, drawable, msc, tv_sec, tv_usec,
    664                          DRI2_BLIT_COMPLETE,
    665                          frame_info->client ? frame_info->event_complete : NULL,
    666                          frame_info->event_data);
    667         break;
    668 
    669     case MS_DRI2_WAIT_MSC:
    670         if (frame_info->client)
    671             DRI2WaitMSCComplete(frame_info->client, drawable,
    672                                 msc, tv_sec, tv_usec);
    673         break;
    674 
    675     default:
    676         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
    677                    "%s: unknown vblank event (type %d) received\n", __func__,
    678                    frame_info->type);
    679         break;
    680     }
    681 
    682     ms_dri2_del_frame_event(frame_info);
    683 }
    684 
    685 static void
    686 ms_dri2_frame_event_abort(void *data)
    687 {
    688     ms_dri2_frame_event_ptr frame_info = data;
    689 
    690     ms_dri2_del_frame_event(frame_info);
    691 }
    692 
    693 /**
    694  * Request a DRM event when the requested conditions will be satisfied.
    695  *
    696  * We need to handle the event and ask the server to wake up the client when
    697  * we receive it.
    698  */
    699 static int
    700 ms_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
    701                           CARD64 divisor, CARD64 remainder)
    702 {
    703     ScreenPtr screen = draw->pScreen;
    704     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    705     ms_dri2_frame_event_ptr wait_info;
    706     int ret;
    707     xf86CrtcPtr crtc = ms_dri2_crtc_covering_drawable(draw);
    708     CARD64 current_msc, current_ust, request_msc;
    709     uint32_t seq;
    710     uint64_t queued_msc;
    711 
    712     /* Drawable not visible, return immediately */
    713     if (!crtc)
    714         goto out_complete;
    715 
    716     wait_info = calloc(1, sizeof(*wait_info));
    717     if (!wait_info)
    718         goto out_complete;
    719 
    720     wait_info->screen = screen;
    721     wait_info->drawable = draw;
    722     wait_info->client = client;
    723     wait_info->type = MS_DRI2_WAIT_MSC;
    724 
    725     if (!ms_dri2_add_frame_event(wait_info)) {
    726         free(wait_info);
    727         wait_info = NULL;
    728         goto out_complete;
    729     }
    730 
    731     /* Get current count */
    732     ret = ms_get_crtc_ust_msc(crtc, &current_ust, &current_msc);
    733 
    734     /*
    735      * If divisor is zero, or current_msc is smaller than target_msc,
    736      * we just need to make sure target_msc passes  before waking up the
    737      * client.
    738      */
    739     if (divisor == 0 || current_msc < target_msc) {
    740         /* If target_msc already reached or passed, set it to
    741          * current_msc to ensure we return a reasonable value back
    742          * to the caller. This keeps the client from continually
    743          * sending us MSC targets from the past by forcibly updating
    744          * their count on this call.
    745          */
    746         seq = ms_drm_queue_alloc(crtc, wait_info,
    747                                  ms_dri2_frame_event_handler,
    748                                  ms_dri2_frame_event_abort);
    749         if (!seq)
    750             goto out_free;
    751 
    752         if (current_msc >= target_msc)
    753             target_msc = current_msc;
    754 
    755         ret = ms_queue_vblank(crtc, MS_QUEUE_ABSOLUTE, target_msc, &queued_msc, seq);
    756         if (!ret) {
    757             static int limit = 5;
    758             if (limit) {
    759                 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
    760                            "%s:%d get vblank counter failed: %s\n",
    761                            __FUNCTION__, __LINE__,
    762                            strerror(errno));
    763                 limit--;
    764             }
    765             goto out_free;
    766         }
    767 
    768         wait_info->frame = queued_msc;
    769         DRI2BlockClient(client, draw);
    770         return TRUE;
    771     }
    772 
    773     /*
    774      * If we get here, target_msc has already passed or we don't have one,
    775      * so we queue an event that will satisfy the divisor/remainder equation.
    776      */
    777     request_msc = current_msc - (current_msc % divisor) +
    778         remainder;
    779     /*
    780      * If calculated remainder is larger than requested remainder,
    781      * it means we've passed the last point where
    782      * seq % divisor == remainder, so we need to wait for the next time
    783      * that will happen.
    784      */
    785     if ((current_msc % divisor) >= remainder)
    786         request_msc += divisor;
    787 
    788     seq = ms_drm_queue_alloc(crtc, wait_info,
    789                              ms_dri2_frame_event_handler,
    790                              ms_dri2_frame_event_abort);
    791     if (!seq)
    792         goto out_free;
    793 
    794     if (!ms_queue_vblank(crtc, MS_QUEUE_ABSOLUTE, request_msc, &queued_msc, seq)) {
    795         static int limit = 5;
    796         if (limit) {
    797             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
    798                        "%s:%d get vblank counter failed: %s\n",
    799                        __FUNCTION__, __LINE__,
    800                        strerror(errno));
    801             limit--;
    802         }
    803         goto out_free;
    804     }
    805 
    806     wait_info->frame = queued_msc;
    807 
    808     DRI2BlockClient(client, draw);
    809 
    810     return TRUE;
    811 
    812  out_free:
    813     ms_dri2_del_frame_event(wait_info);
    814  out_complete:
    815     DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
    816     return TRUE;
    817 }
    818 
    819 /**
    820  * ScheduleSwap is responsible for requesting a DRM vblank event for
    821  * the appropriate frame, or executing the swap immediately if it
    822  * doesn't need to wait.
    823  *
    824  * When the swap is complete, the driver should call into the server so it
    825  * can send any swap complete events that have been requested.
    826  */
    827 static int
    828 ms_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
    829                       DRI2BufferPtr front, DRI2BufferPtr back,
    830                       CARD64 *target_msc, CARD64 divisor,
    831                       CARD64 remainder, DRI2SwapEventPtr func, void *data)
    832 {
    833     ScreenPtr screen = draw->pScreen;
    834     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    835     int ret, flip = 0;
    836     xf86CrtcPtr crtc = ms_dri2_crtc_covering_drawable(draw);
    837     ms_dri2_frame_event_ptr frame_info = NULL;
    838     uint64_t current_msc, current_ust;
    839     uint64_t request_msc;
    840     uint32_t seq;
    841     ms_queue_flag ms_flag = MS_QUEUE_ABSOLUTE;
    842     uint64_t queued_msc;
    843 
    844     /* Drawable not displayed... just complete the swap */
    845     if (!crtc)
    846         goto blit_fallback;
    847 
    848     frame_info = calloc(1, sizeof(*frame_info));
    849     if (!frame_info)
    850         goto blit_fallback;
    851 
    852     frame_info->screen = screen;
    853     frame_info->drawable = draw;
    854     frame_info->client = client;
    855     frame_info->event_complete = func;
    856     frame_info->event_data = data;
    857     frame_info->front = front;
    858     frame_info->back = back;
    859     frame_info->crtc = crtc;
    860     frame_info->type = MS_DRI2_QUEUE_SWAP;
    861 
    862     if (!ms_dri2_add_frame_event(frame_info)) {
    863         free(frame_info);
    864         frame_info = NULL;
    865         goto blit_fallback;
    866     }
    867 
    868     ms_dri2_reference_buffer(front);
    869     ms_dri2_reference_buffer(back);
    870 
    871     ret = ms_get_crtc_ust_msc(crtc, &current_ust, &current_msc);
    872     if (ret != Success)
    873         goto blit_fallback;
    874 
    875     /* Flips need to be submitted one frame before */
    876     if (can_flip(scrn, draw, front, back)) {
    877         frame_info->type = MS_DRI2_QUEUE_FLIP;
    878         flip = 1;
    879     }
    880 
    881     /* Correct target_msc by 'flip' if frame_info->type == MS_DRI2_QUEUE_FLIP.
    882      * Do it early, so handling of different timing constraints
    883      * for divisor, remainder and msc vs. target_msc works.
    884      */
    885     if (*target_msc > 0)
    886         *target_msc -= flip;
    887 
    888     /* If non-pageflipping, but blitting/exchanging, we need to use
    889      * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
    890      * on.
    891      */
    892     if (flip == 0)
    893         ms_flag |= MS_QUEUE_NEXT_ON_MISS;
    894 
    895     /*
    896      * If divisor is zero, or current_msc is smaller than target_msc
    897      * we just need to make sure target_msc passes before initiating
    898      * the swap.
    899      */
    900     if (divisor == 0 || current_msc < *target_msc) {
    901 
    902         /* If target_msc already reached or passed, set it to
    903          * current_msc to ensure we return a reasonable value back
    904          * to the caller. This makes swap_interval logic more robust.
    905          */
    906         if (current_msc >= *target_msc)
    907             *target_msc = current_msc;
    908 
    909         seq = ms_drm_queue_alloc(crtc, frame_info,
    910                                  ms_dri2_frame_event_handler,
    911                                  ms_dri2_frame_event_abort);
    912         if (!seq)
    913             goto blit_fallback;
    914 
    915         if (!ms_queue_vblank(crtc, ms_flag, *target_msc, &queued_msc, seq)) {
    916             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
    917                        "divisor 0 get vblank counter failed: %s\n",
    918                        strerror(errno));
    919             goto blit_fallback;
    920         }
    921 
    922         *target_msc = queued_msc + flip;
    923         frame_info->frame = *target_msc;
    924 
    925         return TRUE;
    926     }
    927 
    928     /*
    929      * If we get here, target_msc has already passed or we don't have one,
    930      * and we need to queue an event that will satisfy the divisor/remainder
    931      * equation.
    932      */
    933 
    934     request_msc = current_msc - (current_msc % divisor) +
    935         remainder;
    936 
    937     /*
    938      * If the calculated deadline vbl.request.sequence is smaller than
    939      * or equal to current_msc, it means we've passed the last point
    940      * when effective onset frame seq could satisfy
    941      * seq % divisor == remainder, so we need to wait for the next time
    942      * this will happen.
    943 
    944      * This comparison takes the DRM_VBLANK_NEXTONMISS delay into account.
    945      */
    946     if (request_msc <= current_msc)
    947         request_msc += divisor;
    948 
    949     seq = ms_drm_queue_alloc(crtc, frame_info,
    950                              ms_dri2_frame_event_handler,
    951                              ms_dri2_frame_event_abort);
    952     if (!seq)
    953         goto blit_fallback;
    954 
    955     /* Account for 1 frame extra pageflip delay if flip > 0 */
    956     if (!ms_queue_vblank(crtc, ms_flag, request_msc - flip, &queued_msc, seq)) {
    957         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
    958                    "final get vblank counter failed: %s\n",
    959                    strerror(errno));
    960         goto blit_fallback;
    961     }
    962 
    963     /* Adjust returned value for 1 fame pageflip offset of flip > 0 */
    964     *target_msc = queued_msc + flip;
    965     frame_info->frame = *target_msc;
    966 
    967     return TRUE;
    968 
    969  blit_fallback:
    970     ms_dri2_blit_swap(draw, front, back);
    971     DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
    972     if (frame_info)
    973         ms_dri2_del_frame_event(frame_info);
    974     *target_msc = 0; /* offscreen, so zero out target vblank count */
    975     return TRUE;
    976 }
    977 
    978 static int
    979 ms_dri2_frame_event_client_gone(void *data, XID id)
    980 {
    981     struct ms_dri2_resource *resource = data;
    982 
    983     while (!xorg_list_is_empty(&resource->list)) {
    984         ms_dri2_frame_event_ptr info =
    985             xorg_list_first_entry(&resource->list,
    986                                   ms_dri2_frame_event_rec,
    987                                   client_resource);
    988 
    989         xorg_list_del(&info->client_resource);
    990         info->client = NULL;
    991     }
    992     free(resource);
    993 
    994     return Success;
    995 }
    996 
    997 static int
    998 ms_dri2_frame_event_drawable_gone(void *data, XID id)
    999 {
   1000     struct ms_dri2_resource *resource = data;
   1001 
   1002     while (!xorg_list_is_empty(&resource->list)) {
   1003         ms_dri2_frame_event_ptr info =
   1004             xorg_list_first_entry(&resource->list,
   1005                                   ms_dri2_frame_event_rec,
   1006                                   drawable_resource);
   1007 
   1008         xorg_list_del(&info->drawable_resource);
   1009         info->drawable = NULL;
   1010     }
   1011     free(resource);
   1012 
   1013     return Success;
   1014 }
   1015 
   1016 static Bool
   1017 ms_dri2_register_frame_event_resource_types(void)
   1018 {
   1019     frame_event_client_type =
   1020         CreateNewResourceType(ms_dri2_frame_event_client_gone,
   1021                               "Frame Event Client");
   1022     if (!frame_event_client_type)
   1023         return FALSE;
   1024 
   1025     frame_event_drawable_type =
   1026         CreateNewResourceType(ms_dri2_frame_event_drawable_gone,
   1027                               "Frame Event Drawable");
   1028     if (!frame_event_drawable_type)
   1029         return FALSE;
   1030 
   1031     return TRUE;
   1032 }
   1033 
   1034 Bool
   1035 ms_dri2_screen_init(ScreenPtr screen)
   1036 {
   1037     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
   1038     modesettingPtr ms = modesettingPTR(scrn);
   1039     DRI2InfoRec info;
   1040     const char *driver_names[2] = { NULL, NULL };
   1041 
   1042     if (!ms->glamor.supports_pixmap_import_export(screen)) {
   1043         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
   1044                    "DRI2: glamor lacks support for pixmap import/export\n");
   1045     }
   1046 
   1047     if (!xf86LoaderCheckSymbol("DRI2Version"))
   1048         return FALSE;
   1049 
   1050     if (!dixRegisterPrivateKey(&ms_dri2_client_key,
   1051                                PRIVATE_CLIENT, sizeof(XID)))
   1052         return FALSE;
   1053 
   1054     if (serverGeneration != ms_dri2_server_generation) {
   1055         ms_dri2_server_generation = serverGeneration;
   1056         if (!ms_dri2_register_frame_event_resource_types()) {
   1057             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
   1058                        "Cannot register DRI2 frame event resources\n");
   1059             return FALSE;
   1060         }
   1061     }
   1062 
   1063     memset(&info, '\0', sizeof(info));
   1064     info.fd = ms->fd;
   1065     info.driverName = NULL; /* Compat field, unused. */
   1066     info.deviceName = drmGetDeviceNameFromFd(ms->fd);
   1067 
   1068     info.version = 9;
   1069     info.CreateBuffer = ms_dri2_create_buffer;
   1070     info.DestroyBuffer = ms_dri2_destroy_buffer;
   1071     info.CopyRegion = ms_dri2_copy_region;
   1072     info.ScheduleSwap = ms_dri2_schedule_swap;
   1073     info.GetMSC = ms_dri2_get_msc;
   1074     info.ScheduleWaitMSC = ms_dri2_schedule_wait_msc;
   1075     info.CreateBuffer2 = ms_dri2_create_buffer2;
   1076     info.DestroyBuffer2 = ms_dri2_destroy_buffer2;
   1077     info.CopyRegion2 = ms_dri2_copy_region2;
   1078 
   1079     /* Ask Glamor to obtain the DRI driver name via EGL_MESA_query_driver, */
   1080     if (ms->glamor.egl_get_driver_name)
   1081         driver_names[0] = ms->glamor.egl_get_driver_name(screen);
   1082 
   1083     if (driver_names[0]) {
   1084         /* There is no VDPAU driver for Intel, fallback to the generic
   1085          * OpenGL/VAAPI va_gl backend to emulate VDPAU.  Otherwise,
   1086          * guess that the DRI and VDPAU drivers have the same name.
   1087          */
   1088         if (strcmp(driver_names[0], "i965") == 0 ||
   1089             strcmp(driver_names[0], "iris") == 0 ||
   1090             strcmp(driver_names[0], "crocus") == 0) {
   1091             driver_names[1] = "va_gl";
   1092         } else {
   1093             driver_names[1] = driver_names[0];
   1094         }
   1095 
   1096         info.numDrivers = 2;
   1097         info.driverNames = driver_names;
   1098     } else {
   1099         /* EGL_MESA_query_driver was unavailable; let dri2.c select the
   1100          * driver and fill in these fields for us.
   1101          */
   1102         info.numDrivers = 0;
   1103         info.driverNames = NULL;
   1104     }
   1105 
   1106     return DRI2ScreenInit(screen, &info);
   1107 }
   1108 
   1109 void
   1110 ms_dri2_close_screen(ScreenPtr screen)
   1111 {
   1112     DRI2CloseScreen(screen);
   1113 }
   1114 
   1115 #endif /* GLAMOR_HAS_GBM */