Home | History | Annotate | Line # | Download | only in dri2
      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 Hgsberg (krh (at) 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 = NULL;
    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;
    360     XID dri2_id;
    361     int rc;
    362 
    363     if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
    364         return BadValue;
    365 
    366     dri2_client = dri2ClientPrivate(client);
    367 
    368     pPriv = DRI2GetDrawable(pDraw);
    369     if (pPriv == NULL)
    370         pPriv = DRI2AllocateDrawable(pDraw);
    371     if (pPriv == NULL)
    372         return BadAlloc;
    373 
    374     pPriv->prime_id = dri2_client->prime_id;
    375 
    376     dri2_id = FakeClientID(client->index);
    377     rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv);
    378     if (rc != Success)
    379         return rc;
    380 
    381     if (dri2_id_out)
    382         *dri2_id_out = dri2_id;
    383 
    384     return Success;
    385 }
    386 
    387 int
    388 DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
    389                    DRI2InvalidateProcPtr invalidate, void *priv)
    390 {
    391     return DRI2CreateDrawable2(client, pDraw, id, invalidate, priv, NULL);
    392 }
    393 
    394 static int
    395 DRI2DrawableGone(void *p, XID id)
    396 {
    397     DRI2DrawablePtr pPriv = p;
    398     DRI2DrawableRefPtr ref, next;
    399     WindowPtr pWin;
    400     PixmapPtr pPixmap;
    401     DrawablePtr pDraw;
    402     int i;
    403 
    404     xorg_list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
    405         if (ref->dri2_id == id) {
    406             xorg_list_del(&ref->link);
    407             /* If this was the last ref under this X drawable XID,
    408              * unregister the X drawable resource. */
    409             if (!DRI2LookupDrawableRef(pPriv, ref->id))
    410                 FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
    411             free(ref);
    412             break;
    413         }
    414 
    415         if (ref->id == id) {
    416             xorg_list_del(&ref->link);
    417             FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
    418             free(ref);
    419         }
    420     }
    421 
    422     if (!xorg_list_is_empty(&pPriv->reference_list))
    423         return Success;
    424 
    425     pDraw = pPriv->drawable;
    426     if (pDraw->type == DRAWABLE_WINDOW) {
    427         pWin = (WindowPtr) pDraw;
    428         dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL);
    429     }
    430     else {
    431         pPixmap = (PixmapPtr) pDraw;
    432         dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
    433     }
    434 
    435     if (pPriv->prime_secondary_pixmap) {
    436         (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap);
    437         (*pPriv->prime_secondary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap);
    438     }
    439 
    440     if (pPriv->buffers != NULL) {
    441         for (i = 0; i < pPriv->bufferCount; i++)
    442             destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
    443 
    444         free(pPriv->buffers);
    445     }
    446 
    447     if (pPriv->redirectpixmap) {
    448         (*pDraw->pScreen->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
    449         (*pDraw->pScreen->DestroyPixmap)(pPriv->redirectpixmap);
    450     }
    451 
    452     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
    453     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_MSC);
    454     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SBC);
    455 
    456     free(pPriv);
    457 
    458     return Success;
    459 }
    460 
    461 static DRI2BufferPtr
    462 create_buffer(DRI2ScreenPtr ds, DrawablePtr pDraw,
    463               unsigned int attachment, unsigned int format)
    464 {
    465     DRI2BufferPtr buffer;
    466     if (ds->CreateBuffer2)
    467         buffer = (*ds->CreateBuffer2)(GetScreenPrime(pDraw->pScreen,
    468                                                      DRI2GetDrawable(pDraw)->prime_id),
    469                                       pDraw, attachment, format);
    470     else
    471         buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
    472     return buffer;
    473 }
    474 
    475 static void
    476 destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id)
    477 {
    478     ScreenPtr primeScreen;
    479     DRI2ScreenPtr ds;
    480     primeScreen = GetScreenPrime(pDraw->pScreen, prime_id);
    481     ds = DRI2GetScreen(primeScreen);
    482     if (ds->DestroyBuffer2)
    483         (*ds->DestroyBuffer2)(primeScreen, pDraw, buffer);
    484     else
    485         (*ds->DestroyBuffer)(pDraw, buffer);
    486 }
    487 
    488 static int
    489 find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
    490 {
    491     int i;
    492 
    493     if (pPriv->buffers == NULL) {
    494         return -1;
    495     }
    496 
    497     for (i = 0; i < pPriv->bufferCount; i++) {
    498         if ((pPriv->buffers[i] != NULL)
    499             && (pPriv->buffers[i]->attachment == attachment)) {
    500             return i;
    501         }
    502     }
    503 
    504     return -1;
    505 }
    506 
    507 static Bool
    508 allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
    509                          DRI2DrawablePtr pPriv,
    510                          unsigned int attachment, unsigned int format,
    511                          int dimensions_match, DRI2BufferPtr * buffer)
    512 {
    513     int old_buf = find_attachment(pPriv, attachment);
    514 
    515     if ((old_buf < 0)
    516         || attachment == DRI2BufferFrontLeft
    517         || !dimensions_match || (pPriv->buffers[old_buf]->format != format)) {
    518         *buffer = create_buffer(ds, pDraw, attachment, format);
    519         return TRUE;
    520 
    521     }
    522     else {
    523         *buffer = pPriv->buffers[old_buf];
    524 
    525         if (ds->ReuseBufferNotify)
    526             (*ds->ReuseBufferNotify) (pDraw, *buffer);
    527 
    528         pPriv->buffers[old_buf] = NULL;
    529         return FALSE;
    530     }
    531 }
    532 
    533 static void
    534 update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
    535                              DRI2BufferPtr * buffers, int out_count, int *width,
    536                              int *height)
    537 {
    538     int i;
    539 
    540     if (pPriv->buffers != NULL) {
    541         for (i = 0; i < pPriv->bufferCount; i++) {
    542             if (pPriv->buffers[i] != NULL) {
    543                 destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
    544             }
    545         }
    546 
    547         free(pPriv->buffers);
    548     }
    549 
    550     pPriv->buffers = buffers;
    551     pPriv->bufferCount = out_count;
    552     pPriv->width = pDraw->width;
    553     pPriv->height = pDraw->height;
    554     *width = pPriv->width;
    555     *height = pPriv->height;
    556 }
    557 
    558 static DRI2BufferPtr *
    559 do_get_buffers(DrawablePtr pDraw, int *width, int *height,
    560                unsigned int *attachments, int count, int *out_count,
    561                int has_format)
    562 {
    563     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    564     DRI2ScreenPtr ds;
    565     DRI2BufferPtr *buffers;
    566     unsigned attachments_bitset = 0;
    567     Bool need_real_front = FALSE;
    568     Bool need_fake_front = FALSE;
    569     int front_format = 0;
    570     int dimensions_match;
    571     int buffers_changed = 0;
    572     int i;
    573 
    574     if (!pPriv ||
    575         count > DRI2BufferHiz + 1) {
    576         *width = pDraw->width;
    577         *height = pDraw->height;
    578         *out_count = 0;
    579         return NULL;
    580     }
    581 
    582     ds = DRI2GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
    583 
    584     dimensions_match = (pDraw->width == pPriv->width)
    585         && (pDraw->height == pPriv->height);
    586 
    587     /* Since we deduplicate attachments in the buffers array, there cannot be
    588      * more entries than there are attachments.
    589      */
    590     buffers = calloc((min(count, DRI2BufferHiz) + 1), sizeof(buffers[0]));
    591     if (!buffers)
    592         goto err_out;
    593 
    594     for (i = 0; i < count; i++) {
    595         const unsigned attachment = *(attachments++);
    596         const unsigned format = (has_format) ? *(attachments++) : 0;
    597 
    598         if (attachment > DRI2BufferHiz)
    599             goto err_out;
    600 
    601         if (attachments_bitset & (1u << attachment))
    602             continue;
    603 
    604         attachments_bitset |= 1u << attachment;
    605 
    606         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
    607                                      format, dimensions_match, &buffers[i]))
    608             buffers_changed = 1;
    609 
    610         if (buffers[i] == NULL)
    611             goto err_out;
    612 
    613         /* In certain cases the (fake) front buffer is always needed, so return
    614          * it even if the client failed to request it.
    615          * The logic in & after the loop accounts for the case where the client
    616          * does request the (fake) front buffer, to avoid returning it multiple
    617          * times.
    618          */
    619         if (attachment == DRI2BufferBackLeft) {
    620             need_real_front = TRUE;
    621             front_format = format;
    622         }
    623 
    624         if (attachment == DRI2BufferFrontLeft) {
    625             front_format = format;
    626 
    627             if (pDraw->type == DRAWABLE_WINDOW)
    628                 need_fake_front = TRUE;
    629         }
    630     }
    631 
    632     if (need_real_front &&
    633         !(attachments_bitset & (1u << DRI2BufferFrontLeft))) {
    634         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft,
    635                                      front_format, dimensions_match,
    636                                      &buffers[i]))
    637             buffers_changed = 1;
    638 
    639         if (buffers[i] == NULL)
    640             goto err_out;
    641         i++;
    642     }
    643 
    644     if (need_fake_front &&
    645         !(attachments_bitset & (1u << DRI2BufferFakeFrontLeft))) {
    646         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft,
    647                                      front_format, dimensions_match,
    648                                      &buffers[i]))
    649             buffers_changed = 1;
    650 
    651         if (buffers[i] == NULL)
    652             goto err_out;
    653 
    654         i++;
    655         attachments_bitset |= 1u << DRI2BufferFakeFrontLeft;
    656     }
    657 
    658     *out_count = i;
    659 
    660     update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width,
    661                                  height);
    662 
    663     /* If the client is getting a fake front-buffer, pre-fill it with the
    664      * contents of the real front-buffer.  This ensures correct operation of
    665      * applications that call glXWaitX before calling glDrawBuffer.
    666      */
    667     if (buffers_changed &&
    668         (attachments_bitset & (1u << DRI2BufferFakeFrontLeft))) {
    669         BoxRec box;
    670         RegionRec region;
    671 
    672         box.x1 = 0;
    673         box.y1 = 0;
    674         box.x2 = pPriv->width;
    675         box.y2 = pPriv->height;
    676         RegionInit(&region, &box, 0);
    677 
    678         DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
    679                        DRI2BufferFrontLeft);
    680     }
    681 
    682     pPriv->needInvalidate = TRUE;
    683 
    684     return pPriv->buffers;
    685 
    686  err_out:
    687 
    688     *out_count = 0;
    689 
    690     if (buffers) {
    691         for (i = 0; i < count; i++) {
    692             if (buffers[i] != NULL)
    693                 destroy_buffer(pDraw, buffers[i], 0);
    694         }
    695 
    696         free(buffers);
    697         buffers = NULL;
    698     }
    699 
    700     update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width,
    701                                  height);
    702 
    703     return buffers;
    704 }
    705 
    706 DRI2BufferPtr *
    707 DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
    708                unsigned int *attachments, int count, int *out_count)
    709 {
    710     return do_get_buffers(pDraw, width, height, attachments, count,
    711                           out_count, FALSE);
    712 }
    713 
    714 DRI2BufferPtr *
    715 DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
    716                          unsigned int *attachments, int count, int *out_count)
    717 {
    718     return do_get_buffers(pDraw, width, height, attachments, count,
    719                           out_count, TRUE);
    720 }
    721 
    722 static void
    723 DRI2InvalidateDrawable(DrawablePtr pDraw)
    724 {
    725     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    726     DRI2DrawableRefPtr ref = NULL;
    727 
    728     if (!pPriv || !pPriv->needInvalidate)
    729         return;
    730 
    731     pPriv->needInvalidate = FALSE;
    732 
    733     xorg_list_for_each_entry(ref, &pPriv->reference_list, link)
    734         ref->invalidate(pDraw, ref->priv, ref->id);
    735 }
    736 
    737 /*
    738  * In the direct rendered case, we throttle the clients that have more
    739  * than their share of outstanding swaps (and thus busy buffers) when a
    740  * new GetBuffers request is received.  In the AIGLX case, we allow the
    741  * client to get the new buffers, but throttle when the next GLX request
    742  * comes in (see __glXDRIcontextWait()).
    743  */
    744 Bool
    745 DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw)
    746 {
    747     DRI2DrawablePtr pPriv;
    748 
    749     pPriv = DRI2GetDrawable(pDraw);
    750     if (pPriv == NULL)
    751         return FALSE;
    752 
    753     /* Throttle to swap limit */
    754     if (pPriv->swapsPending >= pPriv->swap_limit) {
    755         if (dri2Sleep(client, pPriv, WAKE_SWAP)) {
    756             ResetCurrentRequest(client);
    757             client->sequence--;
    758             return TRUE;
    759         }
    760     }
    761 
    762     return FALSE;
    763 }
    764 
    765 void
    766 DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
    767 {
    768     DRI2DrawablePtr pPriv;
    769 
    770     pPriv = DRI2GetDrawable(pDraw);
    771     if (pPriv == NULL)
    772         return;
    773 
    774     dri2Sleep(client, pPriv, WAKE_MSC);
    775 }
    776 
    777 static inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable)
    778 {
    779     if (drawable->type == DRAWABLE_PIXMAP)
    780         return (PixmapPtr)drawable;
    781     else {
    782         struct _Window *pWin = (struct _Window *)drawable;
    783         return drawable->pScreen->GetWindowPixmap(pWin);
    784     }
    785 }
    786 
    787 /*
    788  * A TraverseTree callback to invalidate all windows using the same
    789  * pixmap
    790  */
    791 static int
    792 DRI2InvalidateWalk(WindowPtr pWin, void *data)
    793 {
    794     if (pWin->drawable.pScreen->GetWindowPixmap(pWin) != data)
    795         return WT_DONTWALKCHILDREN;
    796     DRI2InvalidateDrawable(&pWin->drawable);
    797     return WT_WALKCHILDREN;
    798 }
    799 
    800 static void
    801 DRI2InvalidateDrawableAll(DrawablePtr pDraw)
    802 {
    803     if (pDraw->type == DRAWABLE_WINDOW) {
    804         WindowPtr pWin = (WindowPtr) pDraw;
    805         PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
    806 
    807         /*
    808          * Find the top-most window using this pixmap
    809          */
    810         while (pWin->parent &&
    811                pDraw->pScreen->GetWindowPixmap(pWin->parent) == pPixmap)
    812             pWin = pWin->parent;
    813 
    814         /*
    815          * Walk the sub-tree to invalidate all of the
    816          * windows using the same pixmap
    817          */
    818         TraverseTree(pWin, DRI2InvalidateWalk, pPixmap);
    819         DRI2InvalidateDrawable(&pPixmap->drawable);
    820     }
    821     else
    822         DRI2InvalidateDrawable(pDraw);
    823 }
    824 
    825 DrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest)
    826 {
    827     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    828     PixmapPtr spix;
    829     PixmapPtr mpix = GetDrawablePixmap(pDraw);
    830     ScreenPtr primary, secondary;
    831     Bool ret;
    832 
    833     primary = mpix->drawable.pScreen;
    834 
    835     if (pDraw->type == DRAWABLE_WINDOW) {
    836         WindowPtr pWin = (WindowPtr)pDraw;
    837         PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
    838 
    839         if (pDraw->pScreen->GetScreenPixmap(pDraw->pScreen) == pPixmap) {
    840             if (pPriv->redirectpixmap &&
    841                 pPriv->redirectpixmap->drawable.width == pDraw->width &&
    842                 pPriv->redirectpixmap->drawable.height == pDraw->height &&
    843                 pPriv->redirectpixmap->drawable.depth == pDraw->depth) {
    844                 mpix = pPriv->redirectpixmap;
    845             } else {
    846                 if (primary->ReplaceScanoutPixmap) {
    847                     mpix = (*primary->CreatePixmap)(primary, pDraw->width, pDraw->height,
    848                                                    pDraw->depth, CREATE_PIXMAP_USAGE_SHARED);
    849                     if (!mpix)
    850                         return NULL;
    851 
    852                     ret = (*primary->ReplaceScanoutPixmap)(pDraw, mpix, TRUE);
    853                     if (ret == FALSE) {
    854                         (*primary->DestroyPixmap)(mpix);
    855                         return NULL;
    856                     }
    857                     pPriv->redirectpixmap = mpix;
    858                 } else
    859                     return NULL;
    860             }
    861         } else if (pPriv->redirectpixmap) {
    862             (*primary->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
    863             (*primary->DestroyPixmap)(pPriv->redirectpixmap);
    864             pPriv->redirectpixmap = NULL;
    865         }
    866     }
    867 
    868     secondary = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
    869 
    870     /* check if the pixmap is still fine */
    871     if (pPriv->prime_secondary_pixmap) {
    872         if (pPriv->prime_secondary_pixmap->primary_pixmap == mpix)
    873             return &pPriv->prime_secondary_pixmap->drawable;
    874         else {
    875             PixmapUnshareSecondaryPixmap(pPriv->prime_secondary_pixmap);
    876             (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap);
    877             (*secondary->DestroyPixmap)(pPriv->prime_secondary_pixmap);
    878             pPriv->prime_secondary_pixmap = NULL;
    879         }
    880     }
    881 
    882     spix = PixmapShareToSecondary(mpix, secondary);
    883     if (!spix)
    884         return NULL;
    885 
    886     pPriv->prime_secondary_pixmap = spix;
    887 #ifdef COMPOSITE
    888     spix->screen_x = mpix->screen_x;
    889     spix->screen_y = mpix->screen_y;
    890 #endif
    891 
    892     DRI2InvalidateDrawableAll(pDraw);
    893     return &spix->drawable;
    894 }
    895 
    896 static void dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
    897                              DRI2BufferPtr pDest, DRI2BufferPtr pSrc)
    898 {
    899     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
    900     DRI2ScreenPtr ds;
    901     ScreenPtr primeScreen;
    902 
    903     primeScreen = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
    904     ds = DRI2GetScreen(primeScreen);
    905 
    906     if (ds->CopyRegion2)
    907         (*ds->CopyRegion2)(primeScreen, pDraw, pRegion, pDest, pSrc);
    908     else
    909         (*ds->CopyRegion) (pDraw, pRegion, pDest, pSrc);
    910 
    911     /* cause damage to the box */
    912     if (pPriv->prime_id) {
    913        BoxRec box;
    914        RegionRec region;
    915        box.x1 = 0;
    916        box.x2 = box.x1 + pDraw->width;
    917        box.y1 = 0;
    918        box.y2 = box.y1 + pDraw->height;
    919        RegionInit(&region, &box, 1);
    920        RegionTranslate(&region, pDraw->x, pDraw->y);
    921        DamageRegionAppend(pDraw, &region);
    922        DamageRegionProcessPending(pDraw);
    923        RegionUninit(&region);
    924     }
    925 }
    926 
    927 int
    928 DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
    929                unsigned int dest, unsigned int src)
    930 {
    931     DRI2DrawablePtr pPriv;
    932     DRI2BufferPtr pDestBuffer, pSrcBuffer;
    933     int i;
    934 
    935     pPriv = DRI2GetDrawable(pDraw);
    936     if (pPriv == NULL)
    937         return BadDrawable;
    938 
    939     pDestBuffer = NULL;
    940     pSrcBuffer = NULL;
    941     for (i = 0; i < pPriv->bufferCount; i++) {
    942         if (pPriv->buffers[i]->attachment == dest)
    943             pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
    944         if (pPriv->buffers[i]->attachment == src)
    945             pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
    946     }
    947     if (pSrcBuffer == NULL || pDestBuffer == NULL)
    948         return BadValue;
    949 
    950     dri2_copy_region(pDraw, pRegion, pDestBuffer, pSrcBuffer);
    951 
    952     return Success;
    953 }
    954 
    955 /* Can this drawable be page flipped? */
    956 Bool
    957 DRI2CanFlip(DrawablePtr pDraw)
    958 {
    959     ScreenPtr pScreen = pDraw->pScreen;
    960     WindowPtr pWin, pRoot;
    961     PixmapPtr pWinPixmap, pRootPixmap;
    962 
    963     if (pDraw->type == DRAWABLE_PIXMAP)
    964         return TRUE;
    965 
    966     pRoot = pScreen->root;
    967     pRootPixmap = pScreen->GetWindowPixmap(pRoot);
    968 
    969     pWin = (WindowPtr) pDraw;
    970     pWinPixmap = pScreen->GetWindowPixmap(pWin);
    971     if (pRootPixmap != pWinPixmap)
    972         return FALSE;
    973     if (!RegionEqual(&pWin->clipList, &pRoot->winSize))
    974         return FALSE;
    975 
    976     /* Does the window match the pixmap exactly? */
    977     if (pDraw->x != 0 || pDraw->y != 0 ||
    978 #ifdef COMPOSITE
    979         pDraw->x != pWinPixmap->screen_x || pDraw->y != pWinPixmap->screen_y ||
    980 #endif
    981         pDraw->width != pWinPixmap->drawable.width ||
    982         pDraw->height != pWinPixmap->drawable.height)
    983         return FALSE;
    984 
    985     return TRUE;
    986 }
    987 
    988 /* Can we do a pixmap exchange instead of a blit? */
    989 Bool
    990 DRI2CanExchange(DrawablePtr pDraw)
    991 {
    992     return FALSE;
    993 }
    994 
    995 void
    996 DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame,
    997                     unsigned int tv_sec, unsigned int tv_usec)
    998 {
    999     DRI2DrawablePtr pPriv;
   1000 
   1001     pPriv = DRI2GetDrawable(pDraw);
   1002     if (pPriv == NULL)
   1003         return;
   1004 
   1005     ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec,
   1006                          frame, pPriv->swap_count);
   1007 
   1008     dri2WakeAll(client, pPriv, WAKE_MSC);
   1009 }
   1010 
   1011 static void
   1012 DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
   1013                unsigned int tv_sec, unsigned int tv_usec)
   1014 {
   1015     ScreenPtr pScreen = pDraw->pScreen;
   1016     DRI2DrawablePtr pPriv;
   1017 
   1018     pPriv = DRI2GetDrawable(pDraw);
   1019     if (pPriv == NULL) {
   1020         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1021                    "[DRI2] %s: bad drawable\n", __func__);
   1022         return;
   1023     }
   1024 
   1025     /*
   1026      * Swap completed.
   1027      * Wake the client iff:
   1028      *   - it was waiting on SBC
   1029      *   - was blocked due to GLX make current
   1030      *   - was blocked due to swap throttling
   1031      *   - is not blocked due to an MSC wait
   1032      */
   1033     if (pPriv->target_sbc != -1 && pPriv->target_sbc <= pPriv->swap_count) {
   1034         if (dri2WakeAll(client, pPriv, WAKE_SBC)) {
   1035             ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec,
   1036                                  frame, pPriv->swap_count);
   1037             pPriv->target_sbc = -1;
   1038         }
   1039     }
   1040 
   1041     dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
   1042 }
   1043 
   1044 void
   1045 DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
   1046                  unsigned int tv_sec, unsigned int tv_usec, int type,
   1047                  DRI2SwapEventPtr swap_complete, void *swap_data)
   1048 {
   1049     ScreenPtr pScreen = pDraw->pScreen;
   1050     DRI2DrawablePtr pPriv;
   1051     CARD64 ust = 0;
   1052     BoxRec box;
   1053     RegionRec region;
   1054 
   1055     pPriv = DRI2GetDrawable(pDraw);
   1056     if (pPriv == NULL) {
   1057         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1058                    "[DRI2] %s: bad drawable\n", __func__);
   1059         return;
   1060     }
   1061 
   1062     pPriv->swapsPending--;
   1063     pPriv->swap_count++;
   1064 
   1065     box.x1 = 0;
   1066     box.y1 = 0;
   1067     box.x2 = pDraw->width;
   1068     box.y2 = pDraw->height;
   1069     RegionInit(&region, &box, 0);
   1070     DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
   1071                    DRI2BufferFrontLeft);
   1072 
   1073     ust = ((CARD64) tv_sec * 1000000) + tv_usec;
   1074     if (swap_complete)
   1075         swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count);
   1076 
   1077     pPriv->last_swap_msc = frame;
   1078     pPriv->last_swap_ust = ust;
   1079 
   1080     DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
   1081 }
   1082 
   1083 Bool
   1084 DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
   1085 {
   1086     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
   1087 
   1088     /* If we're currently waiting for a swap on this drawable, reset
   1089      * the request and suspend the client. */
   1090     if (pPriv && pPriv->swapsPending) {
   1091         if (dri2Sleep(client, pPriv, WAKE_SWAP)) {
   1092             ResetCurrentRequest(client);
   1093             client->sequence--;
   1094             return TRUE;
   1095         }
   1096     }
   1097 
   1098     return FALSE;
   1099 }
   1100 
   1101 
   1102 
   1103 int
   1104 DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
   1105                 CARD64 divisor, CARD64 remainder, CARD64 * swap_target,
   1106                 DRI2SwapEventPtr func, void *data)
   1107 {
   1108     ScreenPtr pScreen = pDraw->pScreen;
   1109     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
   1110     DRI2DrawablePtr pPriv;
   1111     DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL;
   1112     int ret, i;
   1113     CARD64 ust, current_msc;
   1114 
   1115     pPriv = DRI2GetDrawable(pDraw);
   1116     if (pPriv == NULL) {
   1117         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1118                    "[DRI2] %s: bad drawable\n", __func__);
   1119         return BadDrawable;
   1120     }
   1121 
   1122     /* According to spec, return expected swapbuffers count SBC after this swap
   1123      * will complete. This is ignored unless we return Success, but it must be
   1124      * initialized on every path where we return Success or the caller will send
   1125      * an uninitialized value off the stack to the client. So let's initialize
   1126      * it as early as possible, just to be sure.
   1127      */
   1128     *swap_target = pPriv->swap_count + pPriv->swapsPending + 1;
   1129 
   1130     for (i = 0; i < pPriv->bufferCount; i++) {
   1131         if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
   1132             pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
   1133         if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
   1134             pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
   1135     }
   1136     if (pSrcBuffer == NULL || pDestBuffer == NULL) {
   1137         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1138                    "[DRI2] %s: drawable has no back or front?\n", __func__);
   1139         return BadDrawable;
   1140     }
   1141 
   1142     /* Old DDX or no swap interval, just blit */
   1143     if (!ds->ScheduleSwap || !pPriv->swap_interval || pPriv->prime_id) {
   1144         BoxRec box;
   1145         RegionRec region;
   1146 
   1147         box.x1 = 0;
   1148         box.y1 = 0;
   1149         box.x2 = pDraw->width;
   1150         box.y2 = pDraw->height;
   1151         RegionInit(&region, &box, 0);
   1152 
   1153         pPriv->swapsPending++;
   1154 
   1155         dri2_copy_region(pDraw, &region, pDestBuffer, pSrcBuffer);
   1156         DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
   1157                          func, data);
   1158         return Success;
   1159     }
   1160 
   1161     /*
   1162      * In the simple glXSwapBuffers case, all params will be 0, and we just
   1163      * need to schedule a swap for the last swap target + the swap interval.
   1164      */
   1165     if (target_msc == 0 && divisor == 0 && remainder == 0) {
   1166         /* If the current vblank count of the drawable's crtc is lower
   1167          * than the count stored in last_swap_target from a previous swap
   1168          * then reinitialize last_swap_target to the current crtc's msc,
   1169          * otherwise the swap will hang. This will happen if the drawable
   1170          * is moved to a crtc with a lower refresh rate, or a crtc that just
   1171          * got enabled.
   1172          */
   1173         if (ds->GetMSC) {
   1174             if (!(*ds->GetMSC) (pDraw, &ust, &current_msc))
   1175                 pPriv->last_swap_target = 0;
   1176 
   1177             if (current_msc < pPriv->last_swap_target)
   1178                 pPriv->last_swap_target = current_msc;
   1179 
   1180         }
   1181 
   1182         /*
   1183          * Swap target for this swap is last swap target + swap interval since
   1184          * we have to account for the current swap count, interval, and the
   1185          * number of pending swaps.
   1186          */
   1187         target_msc = pPriv->last_swap_target + pPriv->swap_interval;
   1188 
   1189     }
   1190 
   1191     pPriv->swapsPending++;
   1192     ret = (*ds->ScheduleSwap) (client, pDraw, pDestBuffer, pSrcBuffer,
   1193                                &target_msc, divisor, remainder, func, data);
   1194     if (!ret) {
   1195         pPriv->swapsPending--;  /* didn't schedule */
   1196         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1197                    "[DRI2] %s: driver failed to schedule swap\n", __func__);
   1198         return BadDrawable;
   1199     }
   1200 
   1201     pPriv->last_swap_target = target_msc;
   1202 
   1203     DRI2InvalidateDrawableAll(pDraw);
   1204 
   1205     return Success;
   1206 }
   1207 
   1208 void
   1209 DRI2SwapInterval(DrawablePtr pDrawable, int interval)
   1210 {
   1211     ScreenPtr pScreen = pDrawable->pScreen;
   1212     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
   1213 
   1214     if (pPriv == NULL) {
   1215         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1216                    "[DRI2] %s: bad drawable\n", __func__);
   1217         return;
   1218     }
   1219 
   1220     /* fixme: check against arbitrary max? */
   1221     pPriv->swap_interval = interval;
   1222 }
   1223 
   1224 int
   1225 DRI2GetMSC(DrawablePtr pDraw, CARD64 * ust, CARD64 * msc, CARD64 * sbc)
   1226 {
   1227     ScreenPtr pScreen = pDraw->pScreen;
   1228     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
   1229     DRI2DrawablePtr pPriv;
   1230     Bool ret;
   1231 
   1232     pPriv = DRI2GetDrawable(pDraw);
   1233     if (pPriv == NULL) {
   1234         xf86DrvMsg(pScreen->myNum, X_ERROR,
   1235                    "[DRI2] %s: bad drawable\n", __func__);
   1236         return BadDrawable;
   1237     }
   1238 
   1239     if (!ds->GetMSC) {
   1240         *ust = 0;
   1241         *msc = 0;
   1242         *sbc = pPriv->swap_count;
   1243         return Success;
   1244     }
   1245 
   1246     /*
   1247      * Spec needs to be updated to include unmapped or redirected
   1248      * drawables
   1249      */
   1250 
   1251     ret = (*ds->GetMSC) (pDraw, ust, msc);
   1252     if (!ret)
   1253         return BadDrawable;
   1254 
   1255     *sbc = pPriv->swap_count;
   1256 
   1257     return Success;
   1258 }
   1259 
   1260 int
   1261 DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
   1262             CARD64 divisor, CARD64 remainder)
   1263 {
   1264     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
   1265     DRI2DrawablePtr pPriv;
   1266     Bool ret;
   1267 
   1268     pPriv = DRI2GetDrawable(pDraw);
   1269     if (pPriv == NULL)
   1270         return BadDrawable;
   1271 
   1272     /* Old DDX just completes immediately */
   1273     if (!ds->ScheduleWaitMSC) {
   1274         DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0);
   1275 
   1276         return Success;
   1277     }
   1278 
   1279     ret =
   1280         (*ds->ScheduleWaitMSC) (client, pDraw, target_msc, divisor, remainder);
   1281     if (!ret)
   1282         return BadDrawable;
   1283 
   1284     return Success;
   1285 }
   1286 
   1287 int
   1288 DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc)
   1289 {
   1290     DRI2DrawablePtr pPriv;
   1291 
   1292     pPriv = DRI2GetDrawable(pDraw);
   1293     if (pPriv == NULL)
   1294         return BadDrawable;
   1295 
   1296     if (pPriv->target_sbc != -1) /* already in use */
   1297         return BadDrawable;
   1298 
   1299     /* target_sbc == 0 means to block until all pending swaps are
   1300      * finished. Recalculate target_sbc to get that behaviour.
   1301      */
   1302     if (target_sbc == 0)
   1303         target_sbc = pPriv->swap_count + pPriv->swapsPending;
   1304 
   1305     /* If current swap count already >= target_sbc, reply and
   1306      * return immediately with (ust, msc, sbc) triplet of
   1307      * most recent completed swap.
   1308      */
   1309     if (pPriv->swap_count >= target_sbc) {
   1310         ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust,
   1311                              pPriv->last_swap_msc, pPriv->swap_count);
   1312         return Success;
   1313     }
   1314 
   1315     if (!dri2Sleep(client, pPriv, WAKE_SBC))
   1316         return BadAlloc;
   1317 
   1318     pPriv->target_sbc = target_sbc;
   1319     return Success;
   1320 }
   1321 
   1322 Bool
   1323 DRI2HasSwapControl(ScreenPtr pScreen)
   1324 {
   1325     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1326 
   1327     return ds->ScheduleSwap && ds->GetMSC;
   1328 }
   1329 
   1330 Bool
   1331 DRI2Connect(ClientPtr client, ScreenPtr pScreen,
   1332             unsigned int driverType, int *fd,
   1333             const char **driverName, const char **deviceName)
   1334 {
   1335     DRI2ScreenPtr ds;
   1336     uint32_t prime_id = DRI2DriverPrimeId(driverType);
   1337     uint32_t driver_id = driverType & 0xffff;
   1338 
   1339     if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
   1340         return FALSE;
   1341 
   1342     ds = DRI2GetScreenPrime(pScreen, prime_id);
   1343     if (ds == NULL)
   1344         return FALSE;
   1345 
   1346     if (driver_id >= ds->numDrivers ||
   1347         !ds->driverNames[driver_id])
   1348         return FALSE;
   1349 
   1350     *driverName = ds->driverNames[driver_id];
   1351     *deviceName = ds->deviceName;
   1352     *fd = ds->fd;
   1353 
   1354     if (client) {
   1355         DRI2ClientPtr dri2_client;
   1356         dri2_client = dri2ClientPrivate(client);
   1357         dri2_client->prime_id = prime_id;
   1358     }
   1359 
   1360     return TRUE;
   1361 }
   1362 
   1363 static int
   1364 DRI2AuthMagic (ScreenPtr pScreen, uint32_t magic)
   1365 {
   1366     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1367     if (ds == NULL)
   1368         return -EINVAL;
   1369 
   1370     return (*ds->LegacyAuthMagic) (ds->fd, magic);
   1371 }
   1372 
   1373 Bool
   1374 DRI2Authenticate(ClientPtr client, ScreenPtr pScreen, uint32_t magic)
   1375 {
   1376     DRI2ScreenPtr ds;
   1377     DRI2ClientPtr dri2_client;
   1378     ScreenPtr primescreen;
   1379 
   1380     if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
   1381         return FALSE;
   1382 
   1383     dri2_client = dri2ClientPrivate(client);
   1384 
   1385     ds = DRI2GetScreenPrime(pScreen, dri2_client->prime_id);
   1386     if (ds == NULL)
   1387         return FALSE;
   1388 
   1389     primescreen = GetScreenPrime(pScreen, dri2_client->prime_id);
   1390     if ((*ds->AuthMagic)(primescreen, magic))
   1391         return FALSE;
   1392     return TRUE;
   1393 }
   1394 
   1395 static int
   1396 DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw,
   1397                  WindowPtr pSib)
   1398 {
   1399     DrawablePtr pDraw = (DrawablePtr) pWin;
   1400     ScreenPtr pScreen = pDraw->pScreen;
   1401     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1402     DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
   1403     int ret;
   1404 
   1405     if (ds->ConfigNotify) {
   1406         pScreen->ConfigNotify = ds->ConfigNotify;
   1407 
   1408         ret = (*pScreen->ConfigNotify) (pWin, x, y, w, h, bw, pSib);
   1409 
   1410         ds->ConfigNotify = pScreen->ConfigNotify;
   1411         pScreen->ConfigNotify = DRI2ConfigNotify;
   1412         if (ret)
   1413             return ret;
   1414     }
   1415 
   1416     if (!dd || (dd->width == w && dd->height == h))
   1417         return Success;
   1418 
   1419     DRI2InvalidateDrawable(pDraw);
   1420     return Success;
   1421 }
   1422 
   1423 static void
   1424 DRI2SetWindowPixmap(WindowPtr pWin, PixmapPtr pPix)
   1425 {
   1426     ScreenPtr pScreen = pWin->drawable.pScreen;
   1427     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1428 
   1429     pScreen->SetWindowPixmap = ds->SetWindowPixmap;
   1430     (*pScreen->SetWindowPixmap) (pWin, pPix);
   1431     ds->SetWindowPixmap = pScreen->SetWindowPixmap;
   1432     pScreen->SetWindowPixmap = DRI2SetWindowPixmap;
   1433 
   1434     DRI2InvalidateDrawable(&pWin->drawable);
   1435 }
   1436 
   1437 #define MAX_PRIME DRI2DriverPrimeMask
   1438 static int
   1439 get_prime_id(void)
   1440 {
   1441     int i;
   1442     /* start at 1, prime id 0 is just normal driver */
   1443     for (i = 1; i < MAX_PRIME; i++) {
   1444          if (prime_id_allocate_bitmask & (1 << i))
   1445              continue;
   1446 
   1447          prime_id_allocate_bitmask |= (1 << i);
   1448          return i;
   1449     }
   1450     return -1;
   1451 }
   1452 
   1453 #include "pci_ids/pci_id_driver_map.h"
   1454 
   1455 static char *
   1456 dri2_probe_driver_name(ScreenPtr pScreen, DRI2InfoPtr info)
   1457 {
   1458 #ifdef WITH_LIBDRM
   1459     int i, j;
   1460     char *driver = NULL;
   1461     drmDevicePtr dev;
   1462 
   1463     /* For non-PCI devices and drmGetDevice fail, just assume that
   1464      * the 3D driver is named the same as the kernel driver. This is
   1465      * currently true for vc4 and msm (freedreno).
   1466      */
   1467     if (drmGetDevice(info->fd, &dev) || dev->bustype != DRM_BUS_PCI) {
   1468         drmVersionPtr version = drmGetVersion(info->fd);
   1469 
   1470         if (!version) {
   1471             xf86DrvMsg(pScreen->myNum, X_ERROR,
   1472                        "[DRI2] Couldn't drmGetVersion() on non-PCI device, "
   1473                        "no driver name found.\n");
   1474             return NULL;
   1475         }
   1476 
   1477         driver = strndup(version->name, version->name_len);
   1478         drmFreeVersion(version);
   1479         return driver;
   1480     }
   1481 
   1482     for (i = 0; driver_map[i].driver; i++) {
   1483         if (dev->deviceinfo.pci->vendor_id != driver_map[i].vendor_id)
   1484             continue;
   1485 
   1486         if (driver_map[i].num_chips_ids == -1) {
   1487              driver = strdup(driver_map[i].driver);
   1488              goto out;
   1489         }
   1490 
   1491         for (j = 0; j < driver_map[i].num_chips_ids; j++) {
   1492             if (driver_map[i].chip_ids[j] == dev->deviceinfo.pci->device_id) {
   1493                 driver = strdup(driver_map[i].driver);
   1494                 goto out;
   1495             }
   1496         }
   1497     }
   1498 
   1499     xf86DrvMsg(pScreen->myNum, X_ERROR,
   1500                "[DRI2] No driver mapping found for PCI device "
   1501                "0x%04x / 0x%04x\n",
   1502                dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id);
   1503 out:
   1504     drmFreeDevice(&dev);
   1505     return driver;
   1506 #else
   1507     return NULL;
   1508 #endif
   1509 }
   1510 
   1511 Bool
   1512 DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
   1513 {
   1514     DRI2ScreenPtr ds;
   1515 
   1516     const char *driverTypeNames[] = {
   1517         "DRI",                  /* DRI2DriverDRI */
   1518         "VDPAU",                /* DRI2DriverVDPAU */
   1519     };
   1520     unsigned int i;
   1521     CARD8 cur_minor;
   1522 
   1523     if (info->version < 3)
   1524         return FALSE;
   1525 
   1526     if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
   1527         return FALSE;
   1528 
   1529     if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0))
   1530         return FALSE;
   1531 
   1532     if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
   1533         return FALSE;
   1534 
   1535     if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DRI2ClientRec)))
   1536         return FALSE;
   1537 
   1538     ds = calloc(1, sizeof *ds);
   1539     if (!ds)
   1540         return FALSE;
   1541 
   1542     ds->screen = pScreen;
   1543     ds->fd = info->fd;
   1544     ds->deviceName = info->deviceName;
   1545     dri2_major = 1;
   1546 
   1547     ds->CreateBuffer = info->CreateBuffer;
   1548     ds->DestroyBuffer = info->DestroyBuffer;
   1549     ds->CopyRegion = info->CopyRegion;
   1550     cur_minor = 1;
   1551 
   1552     if (info->version >= 4) {
   1553         ds->ScheduleSwap = info->ScheduleSwap;
   1554         ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
   1555         ds->GetMSC = info->GetMSC;
   1556         cur_minor = 3;
   1557     }
   1558 
   1559     if (info->version >= 5) {
   1560         ds->LegacyAuthMagic = info->AuthMagic;
   1561     }
   1562 
   1563     if (info->version >= 6) {
   1564         ds->ReuseBufferNotify = info->ReuseBufferNotify;
   1565         ds->SwapLimitValidate = info->SwapLimitValidate;
   1566     }
   1567 
   1568     if (info->version >= 7) {
   1569         ds->GetParam = info->GetParam;
   1570         cur_minor = 4;
   1571     }
   1572 
   1573     if (info->version >= 8) {
   1574         ds->AuthMagic = info->AuthMagic2;
   1575     }
   1576 
   1577     if (info->version >= 9) {
   1578         ds->CreateBuffer2 = info->CreateBuffer2;
   1579         if (info->CreateBuffer2 && pScreen->isGPU) {
   1580             ds->prime_id = get_prime_id();
   1581             if (ds->prime_id == -1) {
   1582                 free(ds);
   1583                 return FALSE;
   1584             }
   1585         }
   1586         ds->DestroyBuffer2 = info->DestroyBuffer2;
   1587         ds->CopyRegion2 = info->CopyRegion2;
   1588     }
   1589 
   1590     /*
   1591      * if the driver doesn't provide an AuthMagic function or the info struct
   1592      * version is too low, call through LegacyAuthMagic
   1593      */
   1594     if (!ds->AuthMagic) {
   1595         ds->AuthMagic = DRI2AuthMagic;
   1596         /*
   1597          * If the driver doesn't provide an AuthMagic function
   1598          * it relies on the old method (using libdrm) or fails
   1599          */
   1600         if (!ds->LegacyAuthMagic)
   1601 #ifdef WITH_LIBDRM
   1602             ds->LegacyAuthMagic = drmAuthMagic;
   1603 #else
   1604             goto err_out;
   1605 #endif
   1606     }
   1607 
   1608     /* Initialize minor if needed and set to minimum provied by DDX */
   1609     if (!dri2_minor || dri2_minor > cur_minor)
   1610         dri2_minor = cur_minor;
   1611 
   1612     if (info->version == 3 || info->numDrivers == 0) {
   1613         /* Driver too old: use the old-style driverName field */
   1614         ds->numDrivers = info->driverName ? 1 : 2;
   1615         ds->driverNames = xallocarray(ds->numDrivers, sizeof(*ds->driverNames));
   1616         if (!ds->driverNames)
   1617             goto err_out;
   1618 
   1619         if (info->driverName) {
   1620             ds->driverNames[0] = info->driverName;
   1621         } else {
   1622             /* FIXME dri2_probe_driver_name() returns a strdup-ed string,
   1623              * currently this gets leaked */
   1624             ds->driverNames[0] = ds->driverNames[1] = dri2_probe_driver_name(pScreen, info);
   1625             if (!ds->driverNames[0])
   1626                 return FALSE;
   1627 
   1628             /* There is no VDPAU driver for i965, fallback to the generic
   1629              * OpenGL/VAAPI va_gl backend to emulate VDPAU on i965. */
   1630             if (strcmp(ds->driverNames[0], "i965") == 0)
   1631                 ds->driverNames[1] = "va_gl";
   1632         }
   1633     }
   1634     else {
   1635         ds->numDrivers = info->numDrivers;
   1636         ds->driverNames = xallocarray(info->numDrivers, sizeof(*ds->driverNames));
   1637         if (!ds->driverNames)
   1638             goto err_out;
   1639         memcpy(ds->driverNames, info->driverNames,
   1640                info->numDrivers * sizeof(*ds->driverNames));
   1641     }
   1642 
   1643     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
   1644 
   1645     ds->ConfigNotify = pScreen->ConfigNotify;
   1646     pScreen->ConfigNotify = DRI2ConfigNotify;
   1647 
   1648     ds->SetWindowPixmap = pScreen->SetWindowPixmap;
   1649     pScreen->SetWindowPixmap = DRI2SetWindowPixmap;
   1650 
   1651     xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n");
   1652     for (i = 0; i < ARRAY_SIZE(driverTypeNames); i++) {
   1653         if (i < ds->numDrivers && ds->driverNames[i]) {
   1654             xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2]   %s driver: %s\n",
   1655                        driverTypeNames[i], ds->driverNames[i]);
   1656         }
   1657     }
   1658 
   1659     return TRUE;
   1660 
   1661  err_out:
   1662     xf86DrvMsg(pScreen->myNum, X_WARNING,
   1663                "[DRI2] Initialization failed for info version %d.\n",
   1664                info->version);
   1665     free(ds);
   1666     return FALSE;
   1667 }
   1668 
   1669 void
   1670 DRI2CloseScreen(ScreenPtr pScreen)
   1671 {
   1672     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
   1673 
   1674     pScreen->ConfigNotify = ds->ConfigNotify;
   1675     pScreen->SetWindowPixmap = ds->SetWindowPixmap;
   1676 
   1677     if (ds->prime_id)
   1678         prime_id_allocate_bitmask &= ~(1 << ds->prime_id);
   1679     free(ds->driverNames);
   1680     free(ds);
   1681     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL);
   1682 }
   1683 
   1684 /* Called by InitExtensions() */
   1685 Bool
   1686 DRI2ModuleSetup(void)
   1687 {
   1688     dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable");
   1689     if (!dri2DrawableRes)
   1690         return FALSE;
   1691 
   1692     return TRUE;
   1693 }
   1694 
   1695 void
   1696 DRI2Version(int *major, int *minor)
   1697 {
   1698     if (major != NULL)
   1699         *major = 1;
   1700 
   1701     if (minor != NULL)
   1702         *minor = 2;
   1703 }
   1704 
   1705 int
   1706 DRI2GetParam(ClientPtr client,
   1707              DrawablePtr drawable,
   1708              CARD64 param,
   1709              BOOL *is_param_recognized,
   1710              CARD64 *value)
   1711 {
   1712     DRI2ScreenPtr ds = DRI2GetScreen(drawable->pScreen);
   1713     char high_byte = (param >> 24);
   1714 
   1715     switch (high_byte) {
   1716     case 0:
   1717         /* Parameter names whose high_byte is 0 are reserved for the X
   1718          * server. The server currently recognizes no parameters.
   1719          */
   1720         goto not_recognized;
   1721     case 1:
   1722         /* Parameter names whose high byte is 1 are reserved for the DDX. */
   1723         if (ds->GetParam)
   1724             return ds->GetParam(client, drawable, param,
   1725                                 is_param_recognized, value);
   1726         else
   1727             goto not_recognized;
   1728     default:
   1729         /* Other parameter names are reserved for future use. They are never
   1730          * recognized.
   1731          */
   1732         goto not_recognized;
   1733     }
   1734 
   1735 not_recognized:
   1736     *is_param_recognized = FALSE;
   1737     return Success;
   1738 }
   1739