xserver

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

dri2.c (48957B)


      1 /*
      2  * Copyright © 2007, 2008 Red Hat, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Soft-
      6  * ware"), to deal in the Software without restriction, including without
      7  * limitation the rights to use, copy, modify, merge, publish, distribute,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, provided that the above copyright
     10  * notice(s) and this permission notice appear in all copies of the Soft-
     11  * ware and that both the above copyright notice(s) and this permission
     12  * notice appear in supporting documentation.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
     16  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
     17  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
     18  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
     19  * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
     22  * MANCE OF THIS SOFTWARE.
     23  *
     24  * Except as contained in this notice, the name of a copyright holder shall
     25  * not be used in advertising or otherwise to promote the sale, use or
     26  * other dealings in this Software without prior written authorization of
     27  * the copyright holder.
     28  *
     29  * Authors:
     30  *   Kristian Høgsberg (krh@redhat.com)
     31  */
     32 
     33 #ifdef HAVE_XORG_CONFIG_H
     34 #include <xorg-config.h>
     35 #endif
     36 
     37 #include <errno.h>
     38 #ifdef WITH_LIBDRM
     39 #include <xf86drm.h>
     40 #endif
     41 #include "list.h"
     42 #include "scrnintstr.h"
     43 #include "windowstr.h"
     44 #include "dixstruct.h"
     45 #include "dri2.h"
     46 #include "dri2int.h"
     47 #include "damage.h"
     48 #include "xf86.h"
     49 
     50 CARD8 dri2_major;               /* version of DRI2 supported by DDX */
     51 CARD8 dri2_minor;
     52 
     53 uint32_t prime_id_allocate_bitmask;
     54 
     55 static DevPrivateKeyRec dri2ScreenPrivateKeyRec;
     56 
     57 #define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec)
     58 
     59 static DevPrivateKeyRec dri2WindowPrivateKeyRec;
     60 
     61 #define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec)
     62 
     63 static DevPrivateKeyRec dri2PixmapPrivateKeyRec;
     64 
     65 #define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec)
     66 
     67 static DevPrivateKeyRec dri2ClientPrivateKeyRec;
     68 
     69 #define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec)
     70 
     71 #define dri2ClientPrivate(_pClient) (dixLookupPrivate(&(_pClient)->devPrivates, \
     72                                                       dri2ClientPrivateKey))
     73 
     74 typedef struct _DRI2Client {
     75     int prime_id;
     76 } DRI2ClientRec, *DRI2ClientPtr;
     77 
     78 static RESTYPE dri2DrawableRes;
     79 
     80 typedef struct _DRI2Screen *DRI2ScreenPtr;
     81 
     82 typedef struct _DRI2Drawable {
     83     DRI2ScreenPtr dri2_screen;
     84     DrawablePtr drawable;
     85     struct xorg_list reference_list;
     86     int width;
     87     int height;
     88     DRI2BufferPtr *buffers;
     89     int bufferCount;
     90     unsigned int swapsPending;
     91     int swap_interval;
     92     CARD64 swap_count;
     93     int64_t target_sbc;         /* -1 means no SBC wait outstanding */
     94     CARD64 last_swap_target;    /* most recently queued swap target */
     95     CARD64 last_swap_msc;       /* msc at completion of most recent swap */
     96     CARD64 last_swap_ust;       /* ust at completion of most recent swap */
     97     int swap_limit;             /* for N-buffering */
     98     unsigned blocked[3];
     99     Bool needInvalidate;
    100     int prime_id;
    101     PixmapPtr prime_secondary_pixmap;
    102     PixmapPtr redirectpixmap;
    103 } DRI2DrawableRec, *DRI2DrawablePtr;
    104 
    105 typedef struct _DRI2Screen {
    106     ScreenPtr screen;
    107     int refcnt;
    108     unsigned int numDrivers;
    109     const char **driverNames;
    110     const char *deviceName;
    111     int fd;
    112     unsigned int lastSequence;
    113     int prime_id;
    114 
    115     DRI2CreateBufferProcPtr CreateBuffer;
    116     DRI2DestroyBufferProcPtr DestroyBuffer;
    117     DRI2CopyRegionProcPtr CopyRegion;
    118     DRI2ScheduleSwapProcPtr ScheduleSwap;
    119     DRI2GetMSCProcPtr GetMSC;
    120     DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC;
    121     DRI2AuthMagic2ProcPtr AuthMagic;
    122     DRI2AuthMagicProcPtr LegacyAuthMagic;
    123     DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify;
    124     DRI2SwapLimitValidateProcPtr SwapLimitValidate;
    125     DRI2GetParamProcPtr GetParam;
    126 
    127     HandleExposuresProcPtr HandleExposures;
    128 
    129     ConfigNotifyProcPtr ConfigNotify;
    130     SetWindowPixmapProcPtr SetWindowPixmap;
    131     DRI2CreateBuffer2ProcPtr CreateBuffer2;
    132     DRI2DestroyBuffer2ProcPtr DestroyBuffer2;
    133     DRI2CopyRegion2ProcPtr CopyRegion2;
    134 } DRI2ScreenRec;
    135 
    136 static void
    137 destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id);
    138 
    139 enum DRI2WakeType {
    140     WAKE_SBC,
    141     WAKE_MSC,
    142     WAKE_SWAP,
    143 };
    144 
    145 #define Wake(c, t) (void *)((uintptr_t)(c) | (t))
    146 
    147 static Bool
    148 dri2WakeClient(ClientPtr client, void *closure)
    149 {
    150     ClientWakeup(client);
    151     return TRUE;
    152 }
    153 
    154 static Bool
    155 dri2WakeAll(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t)
    156 {
    157     int count;
    158 
    159     if (!pPriv->blocked[t])
    160         return FALSE;
    161 
    162     count = ClientSignalAll(client, dri2WakeClient, Wake(pPriv, t));
    163     pPriv->blocked[t] -= count;
    164     return count;
    165 }
    166 
    167 static Bool
    168 dri2Sleep(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t)
    169 {
    170     if (ClientSleep(client, dri2WakeClient, Wake(pPriv, t))) {
    171         pPriv->blocked[t]++;
    172         return TRUE;
    173     }
    174     return FALSE;
    175 }
    176 
    177 static DRI2ScreenPtr
    178 DRI2GetScreen(ScreenPtr pScreen)
    179 {
    180     return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey);
    181 }
    182 
    183 static ScreenPtr
    184 GetScreenPrime(ScreenPtr primary, int prime_id)
    185 {
    186     ScreenPtr secondary;
    187     if (prime_id == 0) {
    188         return primary;
    189     }
    190     xorg_list_for_each_entry(secondary, &primary->secondary_list, secondary_head) {
    191         DRI2ScreenPtr ds;
    192 
    193         if (!secondary->is_offload_secondary)
    194             continue;
    195 
    196         ds = DRI2GetScreen(secondary);
    197         if (ds == NULL)
    198             continue;
    199 
    200         if (ds->prime_id == prime_id)
    201             return secondary;
    202     }
    203     return primary;
    204 }
    205 
    206 static DRI2ScreenPtr
    207 DRI2GetScreenPrime(ScreenPtr primary, int prime_id)
    208 {
    209     ScreenPtr secondary = GetScreenPrime(primary, prime_id);
    210     return DRI2GetScreen(secondary);
    211 }
    212 
    213 static DRI2DrawablePtr
    214 DRI2GetDrawable(DrawablePtr pDraw)
    215 {
    216     WindowPtr pWin;
    217     PixmapPtr pPixmap;
    218 
    219     switch (pDraw->type) {
    220     case DRAWABLE_WINDOW:
    221         pWin = (WindowPtr) pDraw;
    222         return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey);
    223     case DRAWABLE_PIXMAP:
    224         pPixmap = (PixmapPtr) pDraw;
    225         return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey);
    226     default:
    227         return NULL;
    228     }
    229 }
    230 
    231 static DRI2DrawablePtr
    232 DRI2AllocateDrawable(DrawablePtr pDraw)
    233 {
    234     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
    235     DRI2DrawablePtr pPriv;
    236     CARD64 ust;
    237     WindowPtr pWin;
    238     PixmapPtr pPixmap;
    239 
    240     pPriv = malloc(sizeof *pPriv);
    241     if (pPriv == NULL)
    242         return NULL;
    243 
    244     pPriv->dri2_screen = ds;
    245     pPriv->drawable = pDraw;
    246     pPriv->width = pDraw->width;
    247     pPriv->height = pDraw->height;
    248     pPriv->buffers = NULL;
    249     pPriv->bufferCount = 0;
    250     pPriv->swapsPending = 0;
    251     pPriv->swap_count = 0;
    252     pPriv->target_sbc = -1;
    253     pPriv->swap_interval = 1;
    254     /* Initialize last swap target from DDX if possible */
    255     if (!ds->GetMSC || !(*ds->GetMSC) (pDraw, &ust, &pPriv->last_swap_target))
    256         pPriv->last_swap_target = 0;
    257 
    258     memset(pPriv->blocked, 0, sizeof(pPriv->blocked));
    259     pPriv->swap_limit = 1;      /* default to double buffering */
    260     pPriv->last_swap_msc = 0;
    261     pPriv->last_swap_ust = 0;
    262     xorg_list_init(&pPriv->reference_list);
    263     pPriv->needInvalidate = FALSE;
    264     pPriv->redirectpixmap = NULL;
    265     pPriv->prime_secondary_pixmap = NULL;
    266     if (pDraw->type == DRAWABLE_WINDOW) {
    267         pWin = (WindowPtr) pDraw;
    268         dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv);
    269     }
    270     else {
    271         pPixmap = (PixmapPtr) pDraw;
    272         dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv);
    273     }
    274 
    275     return pPriv;
    276 }
    277 
    278 Bool
    279 DRI2SwapLimit(DrawablePtr pDraw, int swap_limit)
    280 {
    281     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    282     DRI2ScreenPtr ds;
    283 
    284     if (!pPriv)
    285         return FALSE;
    286 
    287     ds = pPriv->dri2_screen;
    288 
    289     if (!ds->SwapLimitValidate || !ds->SwapLimitValidate(pDraw, swap_limit))
    290         return FALSE;
    291 
    292     pPriv->swap_limit = swap_limit;
    293 
    294     /* Check throttling */
    295     if (pPriv->swapsPending >= pPriv->swap_limit)
    296         return TRUE;
    297 
    298     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
    299     return TRUE;
    300 }
    301 
    302 typedef struct DRI2DrawableRefRec {
    303     XID id;
    304     XID dri2_id;
    305     DRI2InvalidateProcPtr invalidate;
    306     void *priv;
    307     struct xorg_list link;
    308 } DRI2DrawableRefRec, *DRI2DrawableRefPtr;
    309 
    310 static DRI2DrawableRefPtr
    311 DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id)
    312 {
    313     DRI2DrawableRefPtr ref;
    314 
    315     xorg_list_for_each_entry(ref, &pPriv->reference_list, link) {
    316         if (ref->id == id)
    317             return ref;
    318     }
    319 
    320     return NULL;
    321 }
    322 
    323 static int
    324 DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id,
    325                    DRI2InvalidateProcPtr invalidate, void *priv)
    326 {
    327     DRI2DrawableRefPtr ref;
    328 
    329     ref = malloc(sizeof *ref);
    330     if (ref == NULL)
    331         return BadAlloc;
    332 
    333     if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) {
    334         free(ref);
    335         return BadAlloc;
    336     }
    337     if (!DRI2LookupDrawableRef(pPriv, id))
    338         if (!AddResource(id, dri2DrawableRes, pPriv)) {
    339             FreeResourceByType(dri2_id, dri2DrawableRes, TRUE);
    340             free(ref);
    341             return BadAlloc;
    342         }
    343 
    344     ref->id = id;
    345     ref->dri2_id = dri2_id;
    346     ref->invalidate = invalidate;
    347     ref->priv = priv;
    348     xorg_list_add(&ref->link, &pPriv->reference_list);
    349 
    350     return Success;
    351 }
    352 
    353 int
    354 DRI2CreateDrawable2(ClientPtr client, DrawablePtr pDraw, XID id,
    355                     DRI2InvalidateProcPtr invalidate, void *priv,
    356                     XID *dri2_id_out)
    357 {
    358     DRI2DrawablePtr pPriv;
    359     DRI2ClientPtr dri2_client = dri2ClientPrivate(client);
    360     XID dri2_id;
    361     int rc;
    362 
    363     pPriv = DRI2GetDrawable(pDraw);
    364     if (pPriv == NULL)
    365         pPriv = DRI2AllocateDrawable(pDraw);
    366     if (pPriv == NULL)
    367         return BadAlloc;
    368 
    369     pPriv->prime_id = dri2_client->prime_id;
    370 
    371     dri2_id = FakeClientID(client->index);
    372     rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv);
    373     if (rc != Success)
    374         return rc;
    375 
    376     if (dri2_id_out)
    377         *dri2_id_out = dri2_id;
    378 
    379     return Success;
    380 }
    381 
    382 int
    383 DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
    384                    DRI2InvalidateProcPtr invalidate, void *priv)
    385 {
    386     return DRI2CreateDrawable2(client, pDraw, id, invalidate, priv, NULL);
    387 }
    388 
    389 static int
    390 DRI2DrawableGone(void *p, XID id)
    391 {
    392     DRI2DrawablePtr pPriv = p;
    393     DRI2DrawableRefPtr ref, next;
    394     WindowPtr pWin;
    395     PixmapPtr pPixmap;
    396     DrawablePtr pDraw;
    397     int i;
    398 
    399     xorg_list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
    400         if (ref->dri2_id == id) {
    401             xorg_list_del(&ref->link);
    402             /* If this was the last ref under this X drawable XID,
    403              * unregister the X drawable resource. */
    404             if (!DRI2LookupDrawableRef(pPriv, ref->id))
    405                 FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
    406             free(ref);
    407             break;
    408         }
    409 
    410         if (ref->id == id) {
    411             xorg_list_del(&ref->link);
    412             FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
    413             free(ref);
    414         }
    415     }
    416 
    417     if (!xorg_list_is_empty(&pPriv->reference_list))
    418         return Success;
    419 
    420     pDraw = pPriv->drawable;
    421     if (pDraw->type == DRAWABLE_WINDOW) {
    422         pWin = (WindowPtr) pDraw;
    423         dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL);
    424     }
    425     else {
    426         pPixmap = (PixmapPtr) pDraw;
    427         dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
    428     }
    429 
    430     if (pPriv->prime_secondary_pixmap) {
    431         (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap);
    432         (*pPriv->prime_secondary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap);
    433     }
    434 
    435     if (pPriv->buffers != NULL) {
    436         for (i = 0; i < pPriv->bufferCount; i++)
    437             destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
    438 
    439         free(pPriv->buffers);
    440     }
    441 
    442     if (pPriv->redirectpixmap) {
    443         (*pDraw->pScreen->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
    444         (*pDraw->pScreen->DestroyPixmap)(pPriv->redirectpixmap);
    445     }
    446 
    447     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
    448     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_MSC);
    449     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SBC);
    450 
    451     free(pPriv);
    452 
    453     return Success;
    454 }
    455 
    456 static DRI2BufferPtr
    457 create_buffer(DRI2ScreenPtr ds, DrawablePtr pDraw,
    458               unsigned int attachment, unsigned int format)
    459 {
    460     DRI2BufferPtr buffer;
    461     if (ds->CreateBuffer2)
    462         buffer = (*ds->CreateBuffer2)(GetScreenPrime(pDraw->pScreen,
    463                                                      DRI2GetDrawable(pDraw)->prime_id),
    464                                       pDraw, attachment, format);
    465     else
    466         buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
    467     return buffer;
    468 }
    469 
    470 static void
    471 destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id)
    472 {
    473     ScreenPtr primeScreen;
    474     DRI2ScreenPtr ds;
    475     primeScreen = GetScreenPrime(pDraw->pScreen, prime_id);
    476     ds = DRI2GetScreen(primeScreen);
    477     if (ds->DestroyBuffer2)
    478         (*ds->DestroyBuffer2)(primeScreen, pDraw, buffer);
    479     else
    480         (*ds->DestroyBuffer)(pDraw, buffer);
    481 }
    482 
    483 static int
    484 find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
    485 {
    486     int i;
    487 
    488     if (pPriv->buffers == NULL) {
    489         return -1;
    490     }
    491 
    492     for (i = 0; i < pPriv->bufferCount; i++) {
    493         if ((pPriv->buffers[i] != NULL)
    494             && (pPriv->buffers[i]->attachment == attachment)) {
    495             return i;
    496         }
    497     }
    498 
    499     return -1;
    500 }
    501 
    502 static Bool
    503 allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
    504                          DRI2DrawablePtr pPriv,
    505                          unsigned int attachment, unsigned int format,
    506                          int dimensions_match, DRI2BufferPtr * buffer)
    507 {
    508     int old_buf = find_attachment(pPriv, attachment);
    509 
    510     if ((old_buf < 0)
    511         || attachment == DRI2BufferFrontLeft
    512         || !dimensions_match || (pPriv->buffers[old_buf]->format != format)) {
    513         *buffer = create_buffer(ds, pDraw, attachment, format);
    514         return TRUE;
    515 
    516     }
    517     else {
    518         *buffer = pPriv->buffers[old_buf];
    519 
    520         if (ds->ReuseBufferNotify)
    521             (*ds->ReuseBufferNotify) (pDraw, *buffer);
    522 
    523         pPriv->buffers[old_buf] = NULL;
    524         return FALSE;
    525     }
    526 }
    527 
    528 static void
    529 update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
    530                              DRI2BufferPtr * buffers, int out_count, int *width,
    531                              int *height)
    532 {
    533     int i;
    534 
    535     if (pPriv->buffers != NULL) {
    536         for (i = 0; i < pPriv->bufferCount; i++) {
    537             if (pPriv->buffers[i] != NULL) {
    538                 destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
    539             }
    540         }
    541 
    542         free(pPriv->buffers);
    543     }
    544 
    545     pPriv->buffers = buffers;
    546     pPriv->bufferCount = out_count;
    547     pPriv->width = pDraw->width;
    548     pPriv->height = pDraw->height;
    549     *width = pPriv->width;
    550     *height = pPriv->height;
    551 }
    552 
    553 static DRI2BufferPtr *
    554 do_get_buffers(DrawablePtr pDraw, int *width, int *height,
    555                unsigned int *attachments, int count, int *out_count,
    556                int has_format)
    557 {
    558     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    559     DRI2ScreenPtr ds;
    560     DRI2BufferPtr *buffers;
    561     int need_real_front = 0;
    562     int need_fake_front = 0;
    563     int have_fake_front = 0;
    564     int front_format = 0;
    565     int dimensions_match;
    566     int buffers_changed = 0;
    567     int i;
    568 
    569     if (!pPriv) {
    570         *width = pDraw->width;
    571         *height = pDraw->height;
    572         *out_count = 0;
    573         return NULL;
    574     }
    575 
    576     ds = DRI2GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
    577 
    578     dimensions_match = (pDraw->width == pPriv->width)
    579         && (pDraw->height == pPriv->height);
    580 
    581     buffers = calloc((count + 1), sizeof(buffers[0]));
    582     if (!buffers)
    583         goto err_out;
    584 
    585     for (i = 0; i < count; i++) {
    586         const unsigned attachment = *(attachments++);
    587         const unsigned format = (has_format) ? *(attachments++) : 0;
    588 
    589         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
    590                                      format, dimensions_match, &buffers[i]))
    591             buffers_changed = 1;
    592 
    593         if (buffers[i] == NULL)
    594             goto err_out;
    595 
    596         /* If the drawable is a window and the front-buffer is requested,
    597          * silently add the fake front-buffer to the list of requested
    598          * attachments.  The counting logic in the loop accounts for the case
    599          * where the client requests both the fake and real front-buffer.
    600          */
    601         if (attachment == DRI2BufferBackLeft) {
    602             need_real_front++;
    603             front_format = format;
    604         }
    605 
    606         if (attachment == DRI2BufferFrontLeft) {
    607             need_real_front--;
    608             front_format = format;
    609 
    610             if (pDraw->type == DRAWABLE_WINDOW) {
    611                 need_fake_front++;
    612             }
    613         }
    614 
    615         if (pDraw->type == DRAWABLE_WINDOW) {
    616             if (attachment == DRI2BufferFakeFrontLeft) {
    617                 need_fake_front--;
    618                 have_fake_front = 1;
    619             }
    620         }
    621     }
    622 
    623     if (need_real_front > 0) {
    624         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft,
    625                                      front_format, dimensions_match,
    626                                      &buffers[i]))
    627             buffers_changed = 1;
    628 
    629         if (buffers[i] == NULL)
    630             goto err_out;
    631         i++;
    632     }
    633 
    634     if (need_fake_front > 0) {
    635         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft,
    636                                      front_format, dimensions_match,
    637                                      &buffers[i]))
    638             buffers_changed = 1;
    639 
    640         if (buffers[i] == NULL)
    641             goto err_out;
    642 
    643         i++;
    644         have_fake_front = 1;
    645     }
    646 
    647     *out_count = i;
    648 
    649     update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width,
    650                                  height);
    651 
    652     /* If the client is getting a fake front-buffer, pre-fill it with the
    653      * contents of the real front-buffer.  This ensures correct operation of
    654      * applications that call glXWaitX before calling glDrawBuffer.
    655      */
    656     if (have_fake_front && buffers_changed) {
    657         BoxRec box;
    658         RegionRec region;
    659 
    660         box.x1 = 0;
    661         box.y1 = 0;
    662         box.x2 = pPriv->width;
    663         box.y2 = pPriv->height;
    664         RegionInit(&region, &box, 0);
    665 
    666         DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
    667                        DRI2BufferFrontLeft);
    668     }
    669 
    670     pPriv->needInvalidate = TRUE;
    671 
    672     return pPriv->buffers;
    673 
    674  err_out:
    675 
    676     *out_count = 0;
    677 
    678     if (buffers) {
    679         for (i = 0; i < count; i++) {
    680             if (buffers[i] != NULL)
    681                 destroy_buffer(pDraw, buffers[i], 0);
    682         }
    683 
    684         free(buffers);
    685         buffers = NULL;
    686     }
    687 
    688     update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width,
    689                                  height);
    690 
    691     return buffers;
    692 }
    693 
    694 DRI2BufferPtr *
    695 DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
    696                unsigned int *attachments, int count, int *out_count)
    697 {
    698     return do_get_buffers(pDraw, width, height, attachments, count,
    699                           out_count, FALSE);
    700 }
    701 
    702 DRI2BufferPtr *
    703 DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
    704                          unsigned int *attachments, int count, int *out_count)
    705 {
    706     return do_get_buffers(pDraw, width, height, attachments, count,
    707                           out_count, TRUE);
    708 }
    709 
    710 static void
    711 DRI2InvalidateDrawable(DrawablePtr pDraw)
    712 {
    713     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    714     DRI2DrawableRefPtr ref;
    715 
    716     if (!pPriv || !pPriv->needInvalidate)
    717         return;
    718 
    719     pPriv->needInvalidate = FALSE;
    720 
    721     xorg_list_for_each_entry(ref, &pPriv->reference_list, link)
    722         ref->invalidate(pDraw, ref->priv, ref->id);
    723 }
    724 
    725 /*
    726  * In the direct rendered case, we throttle the clients that have more
    727  * than their share of outstanding swaps (and thus busy buffers) when a
    728  * new GetBuffers request is received.  In the AIGLX case, we allow the
    729  * client to get the new buffers, but throttle when the next GLX request
    730  * comes in (see __glXDRIcontextWait()).
    731  */
    732 Bool
    733 DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw)
    734 {
    735     DRI2DrawablePtr pPriv;
    736 
    737     pPriv = DRI2GetDrawable(pDraw);
    738     if (pPriv == NULL)
    739         return FALSE;
    740 
    741     /* Throttle to swap limit */
    742     if (pPriv->swapsPending >= pPriv->swap_limit) {
    743         if (dri2Sleep(client, pPriv, WAKE_SWAP)) {
    744             ResetCurrentRequest(client);
    745             client->sequence--;
    746             return TRUE;
    747         }
    748     }
    749 
    750     return FALSE;
    751 }
    752 
    753 void
    754 DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
    755 {
    756     DRI2DrawablePtr pPriv;
    757 
    758     pPriv = DRI2GetDrawable(pDraw);
    759     if (pPriv == NULL)
    760         return;
    761 
    762     dri2Sleep(client, pPriv, WAKE_MSC);
    763 }
    764 
    765 static inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable)
    766 {
    767     if (drawable->type == DRAWABLE_PIXMAP)
    768         return (PixmapPtr)drawable;
    769     else {
    770         struct _Window *pWin = (struct _Window *)drawable;
    771         return drawable->pScreen->GetWindowPixmap(pWin);
    772     }
    773 }
    774 
    775 /*
    776  * A TraverseTree callback to invalidate all windows using the same
    777  * pixmap
    778  */
    779 static int
    780 DRI2InvalidateWalk(WindowPtr pWin, void *data)
    781 {
    782     if (pWin->drawable.pScreen->GetWindowPixmap(pWin) != data)
    783         return WT_DONTWALKCHILDREN;
    784     DRI2InvalidateDrawable(&pWin->drawable);
    785     return WT_WALKCHILDREN;
    786 }
    787 
    788 static void
    789 DRI2InvalidateDrawableAll(DrawablePtr pDraw)
    790 {
    791     if (pDraw->type == DRAWABLE_WINDOW) {
    792         WindowPtr pWin = (WindowPtr) pDraw;
    793         PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
    794 
    795         /*
    796          * Find the top-most window using this pixmap
    797          */
    798         while (pWin->parent &&
    799                pDraw->pScreen->GetWindowPixmap(pWin->parent) == pPixmap)
    800             pWin = pWin->parent;
    801 
    802         /*
    803          * Walk the sub-tree to invalidate all of the
    804          * windows using the same pixmap
    805          */
    806         TraverseTree(pWin, DRI2InvalidateWalk, pPixmap);
    807         DRI2InvalidateDrawable(&pPixmap->drawable);
    808     }
    809     else
    810         DRI2InvalidateDrawable(pDraw);
    811 }
    812 
    813 DrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest)
    814 {
    815     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    816     PixmapPtr spix;
    817     PixmapPtr mpix = GetDrawablePixmap(pDraw);
    818     ScreenPtr primary, secondary;
    819     Bool ret;
    820 
    821     primary = mpix->drawable.pScreen;
    822 
    823     if (pDraw->type == DRAWABLE_WINDOW) {
    824         WindowPtr pWin = (WindowPtr)pDraw;
    825         PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
    826 
    827         if (pDraw->pScreen->GetScreenPixmap(pDraw->pScreen) == pPixmap) {
    828             if (pPriv->redirectpixmap &&
    829                 pPriv->redirectpixmap->drawable.width == pDraw->width &&
    830                 pPriv->redirectpixmap->drawable.height == pDraw->height &&
    831                 pPriv->redirectpixmap->drawable.depth == pDraw->depth) {
    832                 mpix = pPriv->redirectpixmap;
    833             } else {
    834                 if (primary->ReplaceScanoutPixmap) {
    835                     mpix = (*primary->CreatePixmap)(primary, pDraw->width, pDraw->height,
    836                                                    pDraw->depth, CREATE_PIXMAP_USAGE_SHARED);
    837                     if (!mpix)
    838                         return NULL;
    839 
    840                     ret = (*primary->ReplaceScanoutPixmap)(pDraw, mpix, TRUE);
    841                     if (ret == FALSE) {
    842                         (*primary->DestroyPixmap)(mpix);
    843                         return NULL;
    844                     }
    845                     pPriv->redirectpixmap = mpix;
    846                 } else
    847                     return NULL;
    848             }
    849         } else if (pPriv->redirectpixmap) {
    850             (*primary->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
    851             (*primary->DestroyPixmap)(pPriv->redirectpixmap);
    852             pPriv->redirectpixmap = NULL;
    853         }
    854     }
    855 
    856     secondary = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
    857 
    858     /* check if the pixmap is still fine */
    859     if (pPriv->prime_secondary_pixmap) {
    860         if (pPriv->prime_secondary_pixmap->primary_pixmap == mpix)
    861             return &pPriv->prime_secondary_pixmap->drawable;
    862         else {
    863             PixmapUnshareSecondaryPixmap(pPriv->prime_secondary_pixmap);
    864             (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap);
    865             (*secondary->DestroyPixmap)(pPriv->prime_secondary_pixmap);
    866             pPriv->prime_secondary_pixmap = NULL;
    867         }
    868     }
    869 
    870     spix = PixmapShareToSecondary(mpix, secondary);
    871     if (!spix)
    872         return NULL;
    873 
    874     pPriv->prime_secondary_pixmap = spix;
    875 #ifdef COMPOSITE
    876     spix->screen_x = mpix->screen_x;
    877     spix->screen_y = mpix->screen_y;
    878 #endif
    879 
    880     DRI2InvalidateDrawableAll(pDraw);
    881     return &spix->drawable;
    882 }
    883 
    884 static void dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
    885                              DRI2BufferPtr pDest, DRI2BufferPtr pSrc)
    886 {
    887     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    888     DRI2ScreenPtr ds;
    889     ScreenPtr primeScreen;
    890 
    891     primeScreen = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
    892     ds = DRI2GetScreen(primeScreen);
    893 
    894     if (ds->CopyRegion2)
    895         (*ds->CopyRegion2)(primeScreen, pDraw, pRegion, pDest, pSrc);
    896     else
    897         (*ds->CopyRegion) (pDraw, pRegion, pDest, pSrc);
    898 
    899     /* cause damage to the box */
    900     if (pPriv->prime_id) {
    901        BoxRec box;
    902        RegionRec region;
    903        box.x1 = 0;
    904        box.x2 = box.x1 + pDraw->width;
    905        box.y1 = 0;
    906        box.y2 = box.y1 + pDraw->height;
    907        RegionInit(&region, &box, 1);
    908        RegionTranslate(&region, pDraw->x, pDraw->y);
    909        DamageRegionAppend(pDraw, &region);
    910        DamageRegionProcessPending(pDraw);
    911        RegionUninit(&region);
    912     }
    913 }
    914 
    915 int
    916 DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
    917                unsigned int dest, unsigned int src)
    918 {
    919     DRI2DrawablePtr pPriv;
    920     DRI2BufferPtr pDestBuffer, pSrcBuffer;
    921     int i;
    922 
    923     pPriv = DRI2GetDrawable(pDraw);
    924     if (pPriv == NULL)
    925         return BadDrawable;
    926 
    927     pDestBuffer = NULL;
    928     pSrcBuffer = NULL;
    929     for (i = 0; i < pPriv->bufferCount; i++) {
    930         if (pPriv->buffers[i]->attachment == dest)
    931             pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
    932         if (pPriv->buffers[i]->attachment == src)
    933             pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
    934     }
    935     if (pSrcBuffer == NULL || pDestBuffer == NULL)
    936         return BadValue;
    937 
    938     dri2_copy_region(pDraw, pRegion, pDestBuffer, pSrcBuffer);
    939 
    940     return Success;
    941 }
    942 
    943 /* Can this drawable be page flipped? */
    944 Bool
    945 DRI2CanFlip(DrawablePtr pDraw)
    946 {
    947     ScreenPtr pScreen = pDraw->pScreen;
    948     WindowPtr pWin, pRoot;
    949     PixmapPtr pWinPixmap, pRootPixmap;
    950 
    951     if (pDraw->type == DRAWABLE_PIXMAP)
    952         return TRUE;
    953 
    954     pRoot = pScreen->root;
    955     pRootPixmap = pScreen->GetWindowPixmap(pRoot);
    956 
    957     pWin = (WindowPtr) pDraw;
    958     pWinPixmap = pScreen->GetWindowPixmap(pWin);
    959     if (pRootPixmap != pWinPixmap)
    960         return FALSE;
    961     if (!RegionEqual(&pWin->clipList, &pRoot->winSize))
    962         return FALSE;
    963 
    964     /* Does the window match the pixmap exactly? */
    965     if (pDraw->x != 0 || pDraw->y != 0 ||
    966 #ifdef COMPOSITE
    967         pDraw->x != pWinPixmap->screen_x || pDraw->y != pWinPixmap->screen_y ||
    968 #endif
    969         pDraw->width != pWinPixmap->drawable.width ||
    970         pDraw->height != pWinPixmap->drawable.height)
    971         return FALSE;
    972 
    973     return TRUE;
    974 }
    975 
    976 /* Can we do a pixmap exchange instead of a blit? */
    977 Bool
    978 DRI2CanExchange(DrawablePtr pDraw)
    979 {
    980     return FALSE;
    981 }
    982 
    983 void
    984 DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame,
    985                     unsigned int tv_sec, unsigned int tv_usec)
    986 {
    987     DRI2DrawablePtr pPriv;
    988 
    989     pPriv = DRI2GetDrawable(pDraw);
    990     if (pPriv == NULL)
    991         return;
    992 
    993     ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec,
    994                          frame, pPriv->swap_count);
    995 
    996     dri2WakeAll(client, pPriv, WAKE_MSC);
    997 }
    998 
    999 static void
   1000 DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
   1001                unsigned int tv_sec, unsigned int tv_usec)
   1002 {
   1003     ScreenPtr pScreen = pDraw->pScreen;
   1004     DRI2DrawablePtr pPriv;
   1005 
   1006     pPriv = DRI2GetDrawable(pDraw);
   1007     if (pPriv == NULL) {
   1008         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1009                    "[DRI2] %s: bad drawable\n", __func__);
   1010         return;
   1011     }
   1012 
   1013     /*
   1014      * Swap completed.
   1015      * Wake the client iff:
   1016      *   - it was waiting on SBC
   1017      *   - was blocked due to GLX make current
   1018      *   - was blocked due to swap throttling
   1019      *   - is not blocked due to an MSC wait
   1020      */
   1021     if (pPriv->target_sbc != -1 && pPriv->target_sbc <= pPriv->swap_count) {
   1022         if (dri2WakeAll(client, pPriv, WAKE_SBC)) {
   1023             ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec,
   1024                                  frame, pPriv->swap_count);
   1025             pPriv->target_sbc = -1;
   1026         }
   1027     }
   1028 
   1029     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
   1030 }
   1031 
   1032 void
   1033 DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
   1034                  unsigned int tv_sec, unsigned int tv_usec, int type,
   1035                  DRI2SwapEventPtr swap_complete, void *swap_data)
   1036 {
   1037     ScreenPtr pScreen = pDraw->pScreen;
   1038     DRI2DrawablePtr pPriv;
   1039     CARD64 ust = 0;
   1040     BoxRec box;
   1041     RegionRec region;
   1042 
   1043     pPriv = DRI2GetDrawable(pDraw);
   1044     if (pPriv == NULL) {
   1045         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1046                    "[DRI2] %s: bad drawable\n", __func__);
   1047         return;
   1048     }
   1049 
   1050     pPriv->swapsPending--;
   1051     pPriv->swap_count++;
   1052 
   1053     box.x1 = 0;
   1054     box.y1 = 0;
   1055     box.x2 = pDraw->width;
   1056     box.y2 = pDraw->height;
   1057     RegionInit(&region, &box, 0);
   1058     DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
   1059                    DRI2BufferFrontLeft);
   1060 
   1061     ust = ((CARD64) tv_sec * 1000000) + tv_usec;
   1062     if (swap_complete)
   1063         swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count);
   1064 
   1065     pPriv->last_swap_msc = frame;
   1066     pPriv->last_swap_ust = ust;
   1067 
   1068     DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
   1069 }
   1070 
   1071 Bool
   1072 DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
   1073 {
   1074     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
   1075 
   1076     /* If we're currently waiting for a swap on this drawable, reset
   1077      * the request and suspend the client. */
   1078     if (pPriv && pPriv->swapsPending) {
   1079         if (dri2Sleep(client, pPriv, WAKE_SWAP)) {
   1080             ResetCurrentRequest(client);
   1081             client->sequence--;
   1082             return TRUE;
   1083         }
   1084     }
   1085 
   1086     return FALSE;
   1087 }
   1088 
   1089 
   1090 
   1091 int
   1092 DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
   1093                 CARD64 divisor, CARD64 remainder, CARD64 * swap_target,
   1094                 DRI2SwapEventPtr func, void *data)
   1095 {
   1096     ScreenPtr pScreen = pDraw->pScreen;
   1097     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
   1098     DRI2DrawablePtr pPriv;
   1099     DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL;
   1100     int ret, i;
   1101     CARD64 ust, current_msc;
   1102 
   1103     pPriv = DRI2GetDrawable(pDraw);
   1104     if (pPriv == NULL) {
   1105         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1106                    "[DRI2] %s: bad drawable\n", __func__);
   1107         return BadDrawable;
   1108     }
   1109 
   1110     /* According to spec, return expected swapbuffers count SBC after this swap
   1111      * will complete. This is ignored unless we return Success, but it must be
   1112      * initialized on every path where we return Success or the caller will send
   1113      * an uninitialized value off the stack to the client. So let's initialize
   1114      * it as early as possible, just to be sure.
   1115      */
   1116     *swap_target = pPriv->swap_count + pPriv->swapsPending + 1;
   1117 
   1118     for (i = 0; i < pPriv->bufferCount; i++) {
   1119         if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
   1120             pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
   1121         if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
   1122             pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
   1123     }
   1124     if (pSrcBuffer == NULL || pDestBuffer == NULL) {
   1125         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1126                    "[DRI2] %s: drawable has no back or front?\n", __func__);
   1127         return BadDrawable;
   1128     }
   1129 
   1130     /* Old DDX or no swap interval, just blit */
   1131     if (!ds->ScheduleSwap || !pPriv->swap_interval || pPriv->prime_id) {
   1132         BoxRec box;
   1133         RegionRec region;
   1134 
   1135         box.x1 = 0;
   1136         box.y1 = 0;
   1137         box.x2 = pDraw->width;
   1138         box.y2 = pDraw->height;
   1139         RegionInit(&region, &box, 0);
   1140 
   1141         pPriv->swapsPending++;
   1142 
   1143         dri2_copy_region(pDraw, &region, pDestBuffer, pSrcBuffer);
   1144         DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
   1145                          func, data);
   1146         return Success;
   1147     }
   1148 
   1149     /*
   1150      * In the simple glXSwapBuffers case, all params will be 0, and we just
   1151      * need to schedule a swap for the last swap target + the swap interval.
   1152      */
   1153     if (target_msc == 0 && divisor == 0 && remainder == 0) {
   1154         /* If the current vblank count of the drawable's crtc is lower
   1155          * than the count stored in last_swap_target from a previous swap
   1156          * then reinitialize last_swap_target to the current crtc's msc,
   1157          * otherwise the swap will hang. This will happen if the drawable
   1158          * is moved to a crtc with a lower refresh rate, or a crtc that just
   1159          * got enabled.
   1160          */
   1161         if (ds->GetMSC) {
   1162             if (!(*ds->GetMSC) (pDraw, &ust, &current_msc))
   1163                 pPriv->last_swap_target = 0;
   1164 
   1165             if (current_msc < pPriv->last_swap_target)
   1166                 pPriv->last_swap_target = current_msc;
   1167 
   1168         }
   1169 
   1170         /*
   1171          * Swap target for this swap is last swap target + swap interval since
   1172          * we have to account for the current swap count, interval, and the
   1173          * number of pending swaps.
   1174          */
   1175         target_msc = pPriv->last_swap_target + pPriv->swap_interval;
   1176 
   1177     }
   1178 
   1179     pPriv->swapsPending++;
   1180     ret = (*ds->ScheduleSwap) (client, pDraw, pDestBuffer, pSrcBuffer,
   1181                                &target_msc, divisor, remainder, func, data);
   1182     if (!ret) {
   1183         pPriv->swapsPending--;  /* didn't schedule */
   1184         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1185                    "[DRI2] %s: driver failed to schedule swap\n", __func__);
   1186         return BadDrawable;
   1187     }
   1188 
   1189     pPriv->last_swap_target = target_msc;
   1190 
   1191     DRI2InvalidateDrawableAll(pDraw);
   1192 
   1193     return Success;
   1194 }
   1195 
   1196 void
   1197 DRI2SwapInterval(DrawablePtr pDrawable, int interval)
   1198 {
   1199     ScreenPtr pScreen = pDrawable->pScreen;
   1200     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
   1201 
   1202     if (pPriv == NULL) {
   1203         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1204                    "[DRI2] %s: bad drawable\n", __func__);
   1205         return;
   1206     }
   1207 
   1208     /* fixme: check against arbitrary max? */
   1209     pPriv->swap_interval = interval;
   1210 }
   1211 
   1212 int
   1213 DRI2GetMSC(DrawablePtr pDraw, CARD64 * ust, CARD64 * msc, CARD64 * sbc)
   1214 {
   1215     ScreenPtr pScreen = pDraw->pScreen;
   1216     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
   1217     DRI2DrawablePtr pPriv;
   1218     Bool ret;
   1219 
   1220     pPriv = DRI2GetDrawable(pDraw);
   1221     if (pPriv == NULL) {
   1222         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1223                    "[DRI2] %s: bad drawable\n", __func__);
   1224         return BadDrawable;
   1225     }
   1226 
   1227     if (!ds->GetMSC) {
   1228         *ust = 0;
   1229         *msc = 0;
   1230         *sbc = pPriv->swap_count;
   1231         return Success;
   1232     }
   1233 
   1234     /*
   1235      * Spec needs to be updated to include unmapped or redirected
   1236      * drawables
   1237      */
   1238 
   1239     ret = (*ds->GetMSC) (pDraw, ust, msc);
   1240     if (!ret)
   1241         return BadDrawable;
   1242 
   1243     *sbc = pPriv->swap_count;
   1244 
   1245     return Success;
   1246 }
   1247 
   1248 int
   1249 DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
   1250             CARD64 divisor, CARD64 remainder)
   1251 {
   1252     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
   1253     DRI2DrawablePtr pPriv;
   1254     Bool ret;
   1255 
   1256     pPriv = DRI2GetDrawable(pDraw);
   1257     if (pPriv == NULL)
   1258         return BadDrawable;
   1259 
   1260     /* Old DDX just completes immediately */
   1261     if (!ds->ScheduleWaitMSC) {
   1262         DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0);
   1263 
   1264         return Success;
   1265     }
   1266 
   1267     ret =
   1268         (*ds->ScheduleWaitMSC) (client, pDraw, target_msc, divisor, remainder);
   1269     if (!ret)
   1270         return BadDrawable;
   1271 
   1272     return Success;
   1273 }
   1274 
   1275 int
   1276 DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc)
   1277 {
   1278     DRI2DrawablePtr pPriv;
   1279 
   1280     pPriv = DRI2GetDrawable(pDraw);
   1281     if (pPriv == NULL)
   1282         return BadDrawable;
   1283 
   1284     if (pPriv->target_sbc != -1) /* already in use */
   1285         return BadDrawable;
   1286 
   1287     /* target_sbc == 0 means to block until all pending swaps are
   1288      * finished. Recalculate target_sbc to get that behaviour.
   1289      */
   1290     if (target_sbc == 0)
   1291         target_sbc = pPriv->swap_count + pPriv->swapsPending;
   1292 
   1293     /* If current swap count already >= target_sbc, reply and
   1294      * return immediately with (ust, msc, sbc) triplet of
   1295      * most recent completed swap.
   1296      */
   1297     if (pPriv->swap_count >= target_sbc) {
   1298         ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust,
   1299                              pPriv->last_swap_msc, pPriv->swap_count);
   1300         return Success;
   1301     }
   1302 
   1303     if (!dri2Sleep(client, pPriv, WAKE_SBC))
   1304         return BadAlloc;
   1305 
   1306     pPriv->target_sbc = target_sbc;
   1307     return Success;
   1308 }
   1309 
   1310 Bool
   1311 DRI2HasSwapControl(ScreenPtr pScreen)
   1312 {
   1313     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1314 
   1315     return ds->ScheduleSwap && ds->GetMSC;
   1316 }
   1317 
   1318 Bool
   1319 DRI2Connect(ClientPtr client, ScreenPtr pScreen,
   1320             unsigned int driverType, int *fd,
   1321             const char **driverName, const char **deviceName)
   1322 {
   1323     DRI2ScreenPtr ds;
   1324     uint32_t prime_id = DRI2DriverPrimeId(driverType);
   1325     uint32_t driver_id = driverType & 0xffff;
   1326 
   1327     if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
   1328         return FALSE;
   1329 
   1330     ds = DRI2GetScreenPrime(pScreen, prime_id);
   1331     if (ds == NULL)
   1332         return FALSE;
   1333 
   1334     if (driver_id >= ds->numDrivers ||
   1335         !ds->driverNames[driver_id])
   1336         return FALSE;
   1337 
   1338     *driverName = ds->driverNames[driver_id];
   1339     *deviceName = ds->deviceName;
   1340     *fd = ds->fd;
   1341 
   1342     if (client) {
   1343         DRI2ClientPtr dri2_client;
   1344         dri2_client = dri2ClientPrivate(client);
   1345         dri2_client->prime_id = prime_id;
   1346     }
   1347 
   1348     return TRUE;
   1349 }
   1350 
   1351 static int
   1352 DRI2AuthMagic (ScreenPtr pScreen, uint32_t magic)
   1353 {
   1354     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1355     if (ds == NULL)
   1356         return -EINVAL;
   1357 
   1358     return (*ds->LegacyAuthMagic) (ds->fd, magic);
   1359 }
   1360 
   1361 Bool
   1362 DRI2Authenticate(ClientPtr client, ScreenPtr pScreen, uint32_t magic)
   1363 {
   1364     DRI2ScreenPtr ds;
   1365     DRI2ClientPtr dri2_client = dri2ClientPrivate(client);
   1366     ScreenPtr primescreen;
   1367 
   1368     ds = DRI2GetScreenPrime(pScreen, dri2_client->prime_id);
   1369     if (ds == NULL)
   1370         return FALSE;
   1371 
   1372     primescreen = GetScreenPrime(pScreen, dri2_client->prime_id);
   1373     if ((*ds->AuthMagic)(primescreen, magic))
   1374         return FALSE;
   1375     return TRUE;
   1376 }
   1377 
   1378 static int
   1379 DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw,
   1380                  WindowPtr pSib)
   1381 {
   1382     DrawablePtr pDraw = (DrawablePtr) pWin;
   1383     ScreenPtr pScreen = pDraw->pScreen;
   1384     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1385     DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
   1386     int ret;
   1387 
   1388     if (ds->ConfigNotify) {
   1389         pScreen->ConfigNotify = ds->ConfigNotify;
   1390 
   1391         ret = (*pScreen->ConfigNotify) (pWin, x, y, w, h, bw, pSib);
   1392 
   1393         ds->ConfigNotify = pScreen->ConfigNotify;
   1394         pScreen->ConfigNotify = DRI2ConfigNotify;
   1395         if (ret)
   1396             return ret;
   1397     }
   1398 
   1399     if (!dd || (dd->width == w && dd->height == h))
   1400         return Success;
   1401 
   1402     DRI2InvalidateDrawable(pDraw);
   1403     return Success;
   1404 }
   1405 
   1406 static void
   1407 DRI2SetWindowPixmap(WindowPtr pWin, PixmapPtr pPix)
   1408 {
   1409     ScreenPtr pScreen = pWin->drawable.pScreen;
   1410     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1411 
   1412     pScreen->SetWindowPixmap = ds->SetWindowPixmap;
   1413     (*pScreen->SetWindowPixmap) (pWin, pPix);
   1414     ds->SetWindowPixmap = pScreen->SetWindowPixmap;
   1415     pScreen->SetWindowPixmap = DRI2SetWindowPixmap;
   1416 
   1417     DRI2InvalidateDrawable(&pWin->drawable);
   1418 }
   1419 
   1420 #define MAX_PRIME DRI2DriverPrimeMask
   1421 static int
   1422 get_prime_id(void)
   1423 {
   1424     int i;
   1425     /* start at 1, prime id 0 is just normal driver */
   1426     for (i = 1; i < MAX_PRIME; i++) {
   1427          if (prime_id_allocate_bitmask & (1 << i))
   1428              continue;
   1429 
   1430          prime_id_allocate_bitmask |= (1 << i);
   1431          return i;
   1432     }
   1433     return -1;
   1434 }
   1435 
   1436 #include "pci_ids/pci_id_driver_map.h"
   1437 
   1438 static char *
   1439 dri2_probe_driver_name(ScreenPtr pScreen, DRI2InfoPtr info)
   1440 {
   1441 #ifdef WITH_LIBDRM
   1442     int i, j;
   1443     char *driver = NULL;
   1444     drmDevicePtr dev;
   1445 
   1446     /* For non-PCI devices and drmGetDevice fail, just assume that
   1447      * the 3D driver is named the same as the kernel driver. This is
   1448      * currently true for vc4 and msm (freedreno).
   1449      */
   1450     if (drmGetDevice(info->fd, &dev) || dev->bustype != DRM_BUS_PCI) {
   1451         drmVersionPtr version = drmGetVersion(info->fd);
   1452 
   1453         if (!version) {
   1454             xf86DrvMsg(pScreen->myNum, X_ERROR,
   1455                        "[DRI2] Couldn't drmGetVersion() on non-PCI device, "
   1456                        "no driver name found.\n");
   1457             return NULL;
   1458         }
   1459 
   1460         driver = strndup(version->name, version->name_len);
   1461         drmFreeVersion(version);
   1462         return driver;
   1463     }
   1464 
   1465     for (i = 0; driver_map[i].driver; i++) {
   1466         if (dev->deviceinfo.pci->vendor_id != driver_map[i].vendor_id)
   1467             continue;
   1468 
   1469         if (driver_map[i].num_chips_ids == -1) {
   1470              driver = strdup(driver_map[i].driver);
   1471              goto out;
   1472         }
   1473 
   1474         for (j = 0; j < driver_map[i].num_chips_ids; j++) {
   1475             if (driver_map[i].chip_ids[j] == dev->deviceinfo.pci->device_id) {
   1476                 driver = strdup(driver_map[i].driver);
   1477                 goto out;
   1478             }
   1479         }
   1480     }
   1481 
   1482     xf86DrvMsg(pScreen->myNum, X_ERROR,
   1483                "[DRI2] No driver mapping found for PCI device "
   1484                "0x%04x / 0x%04x\n",
   1485                dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id);
   1486 out:
   1487     drmFreeDevice(&dev);
   1488     return driver;
   1489 #else
   1490     return NULL;
   1491 #endif
   1492 }
   1493 
   1494 Bool
   1495 DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
   1496 {
   1497     DRI2ScreenPtr ds;
   1498 
   1499     const char *driverTypeNames[] = {
   1500         "DRI",                  /* DRI2DriverDRI */
   1501         "VDPAU",                /* DRI2DriverVDPAU */
   1502     };
   1503     unsigned int i;
   1504     CARD8 cur_minor;
   1505 
   1506     if (info->version < 3)
   1507         return FALSE;
   1508 
   1509     if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
   1510         return FALSE;
   1511 
   1512     if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0))
   1513         return FALSE;
   1514 
   1515     if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
   1516         return FALSE;
   1517 
   1518     if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DRI2ClientRec)))
   1519         return FALSE;
   1520 
   1521     ds = calloc(1, sizeof *ds);
   1522     if (!ds)
   1523         return FALSE;
   1524 
   1525     ds->screen = pScreen;
   1526     ds->fd = info->fd;
   1527     ds->deviceName = info->deviceName;
   1528     dri2_major = 1;
   1529 
   1530     ds->CreateBuffer = info->CreateBuffer;
   1531     ds->DestroyBuffer = info->DestroyBuffer;
   1532     ds->CopyRegion = info->CopyRegion;
   1533     cur_minor = 1;
   1534 
   1535     if (info->version >= 4) {
   1536         ds->ScheduleSwap = info->ScheduleSwap;
   1537         ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
   1538         ds->GetMSC = info->GetMSC;
   1539         cur_minor = 3;
   1540     }
   1541 
   1542     if (info->version >= 5) {
   1543         ds->LegacyAuthMagic = info->AuthMagic;
   1544     }
   1545 
   1546     if (info->version >= 6) {
   1547         ds->ReuseBufferNotify = info->ReuseBufferNotify;
   1548         ds->SwapLimitValidate = info->SwapLimitValidate;
   1549     }
   1550 
   1551     if (info->version >= 7) {
   1552         ds->GetParam = info->GetParam;
   1553         cur_minor = 4;
   1554     }
   1555 
   1556     if (info->version >= 8) {
   1557         ds->AuthMagic = info->AuthMagic2;
   1558     }
   1559 
   1560     if (info->version >= 9) {
   1561         ds->CreateBuffer2 = info->CreateBuffer2;
   1562         if (info->CreateBuffer2 && pScreen->isGPU) {
   1563             ds->prime_id = get_prime_id();
   1564             if (ds->prime_id == -1) {
   1565                 free(ds);
   1566                 return FALSE;
   1567             }
   1568         }
   1569         ds->DestroyBuffer2 = info->DestroyBuffer2;
   1570         ds->CopyRegion2 = info->CopyRegion2;
   1571     }
   1572 
   1573     /*
   1574      * if the driver doesn't provide an AuthMagic function or the info struct
   1575      * version is too low, call through LegacyAuthMagic
   1576      */
   1577     if (!ds->AuthMagic) {
   1578         ds->AuthMagic = DRI2AuthMagic;
   1579         /*
   1580          * If the driver doesn't provide an AuthMagic function
   1581          * it relies on the old method (using libdrm) or fails
   1582          */
   1583         if (!ds->LegacyAuthMagic)
   1584 #ifdef WITH_LIBDRM
   1585             ds->LegacyAuthMagic = drmAuthMagic;
   1586 #else
   1587             goto err_out;
   1588 #endif
   1589     }
   1590 
   1591     /* Initialize minor if needed and set to minimum provied by DDX */
   1592     if (!dri2_minor || dri2_minor > cur_minor)
   1593         dri2_minor = cur_minor;
   1594 
   1595     if (info->version == 3 || info->numDrivers == 0) {
   1596         /* Driver too old: use the old-style driverName field */
   1597         ds->numDrivers = info->driverName ? 1 : 2;
   1598         ds->driverNames = xallocarray(ds->numDrivers, sizeof(*ds->driverNames));
   1599         if (!ds->driverNames)
   1600             goto err_out;
   1601 
   1602         if (info->driverName) {
   1603             ds->driverNames[0] = info->driverName;
   1604         } else {
   1605             /* FIXME dri2_probe_driver_name() returns a strdup-ed string,
   1606              * currently this gets leaked */
   1607             ds->driverNames[0] = ds->driverNames[1] = dri2_probe_driver_name(pScreen, info);
   1608             if (!ds->driverNames[0])
   1609                 return FALSE;
   1610 
   1611             /* There is no VDPAU driver for i965, fallback to the generic
   1612              * OpenGL/VAAPI va_gl backend to emulate VDPAU on i965. */
   1613             if (strcmp(ds->driverNames[0], "i965") == 0)
   1614                 ds->driverNames[1] = "va_gl";
   1615         }
   1616     }
   1617     else {
   1618         ds->numDrivers = info->numDrivers;
   1619         ds->driverNames = xallocarray(info->numDrivers, sizeof(*ds->driverNames));
   1620         if (!ds->driverNames)
   1621             goto err_out;
   1622         memcpy(ds->driverNames, info->driverNames,
   1623                info->numDrivers * sizeof(*ds->driverNames));
   1624     }
   1625 
   1626     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
   1627 
   1628     ds->ConfigNotify = pScreen->ConfigNotify;
   1629     pScreen->ConfigNotify = DRI2ConfigNotify;
   1630 
   1631     ds->SetWindowPixmap = pScreen->SetWindowPixmap;
   1632     pScreen->SetWindowPixmap = DRI2SetWindowPixmap;
   1633 
   1634     xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n");
   1635     for (i = 0; i < ARRAY_SIZE(driverTypeNames); i++) {
   1636         if (i < ds->numDrivers && ds->driverNames[i]) {
   1637             xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2]   %s driver: %s\n",
   1638                        driverTypeNames[i], ds->driverNames[i]);
   1639         }
   1640     }
   1641 
   1642     return TRUE;
   1643 
   1644  err_out:
   1645     xf86DrvMsg(pScreen->myNum, X_WARNING,
   1646                "[DRI2] Initialization failed for info version %d.\n",
   1647                info->version);
   1648     free(ds);
   1649     return FALSE;
   1650 }
   1651 
   1652 void
   1653 DRI2CloseScreen(ScreenPtr pScreen)
   1654 {
   1655     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1656 
   1657     pScreen->ConfigNotify = ds->ConfigNotify;
   1658     pScreen->SetWindowPixmap = ds->SetWindowPixmap;
   1659 
   1660     if (ds->prime_id)
   1661         prime_id_allocate_bitmask &= ~(1 << ds->prime_id);
   1662     free(ds->driverNames);
   1663     free(ds);
   1664     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL);
   1665 }
   1666 
   1667 /* Called by InitExtensions() */
   1668 Bool
   1669 DRI2ModuleSetup(void)
   1670 {
   1671     dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable");
   1672     if (!dri2DrawableRes)
   1673         return FALSE;
   1674 
   1675     return TRUE;
   1676 }
   1677 
   1678 void
   1679 DRI2Version(int *major, int *minor)
   1680 {
   1681     if (major != NULL)
   1682         *major = 1;
   1683 
   1684     if (minor != NULL)
   1685         *minor = 2;
   1686 }
   1687 
   1688 int
   1689 DRI2GetParam(ClientPtr client,
   1690              DrawablePtr drawable,
   1691              CARD64 param,
   1692              BOOL *is_param_recognized,
   1693              CARD64 *value)
   1694 {
   1695     DRI2ScreenPtr ds = DRI2GetScreen(drawable->pScreen);
   1696     char high_byte = (param >> 24);
   1697 
   1698     switch (high_byte) {
   1699     case 0:
   1700         /* Parameter names whose high_byte is 0 are reserved for the X
   1701          * server. The server currently recognizes no parameters.
   1702          */
   1703         goto not_recognized;
   1704     case 1:
   1705         /* Parameter names whose high byte is 1 are reserved for the DDX. */
   1706         if (ds->GetParam)
   1707             return ds->GetParam(client, drawable, param,
   1708                                 is_param_recognized, value);
   1709         else
   1710             goto not_recognized;
   1711     default:
   1712         /* Other parameter names are reserved for future use. They are never
   1713          * recognized.
   1714          */
   1715         goto not_recognized;
   1716     }
   1717 
   1718 not_recognized:
   1719     *is_param_recognized = FALSE;
   1720     return Success;
   1721 }