xserver

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

dri.c (76259B)


      1 /**************************************************************************
      2 
      3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
      4 Copyright 2000 VA Linux Systems, Inc.
      5 All Rights Reserved.
      6 
      7 Permission is hereby granted, free of charge, to any person obtaining a
      8 copy of this software and associated documentation files (the
      9 "Software"), to deal in the Software without restriction, including
     10 without limitation the rights to use, copy, modify, merge, publish,
     11 distribute, sub license, and/or sell copies of the Software, and to
     12 permit persons to whom the Software is furnished to do so, subject to
     13 the following conditions:
     14 
     15 The above copyright notice and this permission notice (including the
     16 next paragraph) shall be included in all copies or substantial portions
     17 of the Software.
     18 
     19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     22 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
     23 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26 
     27 **************************************************************************/
     28 
     29 /*
     30  * Authors:
     31  *   Jens Owen <jens@tungstengraphics.com>
     32  *   Rickard E. (Rik) Faith <faith@valinux.com>
     33  *
     34  */
     35 
     36 #ifdef HAVE_XORG_CONFIG_H
     37 #include <xorg-config.h>
     38 #endif
     39 
     40 #include "xf86.h"
     41 #include <sys/time.h>
     42 #include <unistd.h>
     43 #include <string.h>
     44 #include <stdio.h>
     45 #include <sys/ioctl.h>
     46 #include <errno.h>
     47 
     48 #include <X11/X.h>
     49 #include <X11/Xproto.h>
     50 #include "xf86drm.h"
     51 #include "misc.h"
     52 #include "dixstruct.h"
     53 #include "extnsionst.h"
     54 #include "extinit.h"
     55 #include "colormapst.h"
     56 #include "cursorstr.h"
     57 #include "scrnintstr.h"
     58 #include "windowstr.h"
     59 #include "servermd.h"
     60 #define _XF86DRI_SERVER_
     61 #include <X11/dri/xf86driproto.h>
     62 #include "swaprep.h"
     63 #include "xf86str.h"
     64 #include "dri.h"
     65 #include "sarea.h"
     66 #include "dristruct.h"
     67 #include "mi.h"
     68 #include "mipointer.h"
     69 #include "xf86_OSproc.h"
     70 #include "inputstr.h"
     71 #include "xf86VGAarbiter.h"
     72 #include "xf86Extensions.h"
     73 
     74 static int DRIEntPrivIndex = -1;
     75 static DevPrivateKeyRec DRIScreenPrivKeyRec;
     76 
     77 #define DRIScreenPrivKey (&DRIScreenPrivKeyRec)
     78 static DevPrivateKeyRec DRIWindowPrivKeyRec;
     79 
     80 #define DRIWindowPrivKey (&DRIWindowPrivKeyRec)
     81 static unsigned long DRIGeneration = 0;
     82 static unsigned int DRIDrawableValidationStamp = 0;
     83 
     84 static RESTYPE DRIDrawablePrivResType;
     85 static RESTYPE DRIContextPrivResType;
     86 static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv);
     87 
     88 drmServerInfo DRIDRMServerInfo;
     89 
     90                                 /* Wrapper just like xf86DrvMsg, but
     91                                    without the verbosity level checking.
     92                                    This will make it easy to turn off some
     93                                    messages later, based on verbosity
     94                                    level. */
     95 
     96 /*
     97  * Since we're already referencing things from the XFree86 common layer in
     98  * this file, we'd might as well just call xf86VDrvMsgVerb, and have
     99  * consistent message formatting.  The verbosity of these messages can be
    100  * easily changed here.
    101  */
    102 #define DRI_MSG_VERBOSITY 1
    103 
    104 static void
    105 DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...)
    106     _X_ATTRIBUTE_PRINTF(3,4);
    107 
    108 static void
    109 DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...)
    110 {
    111     va_list ap;
    112 
    113     va_start(ap, format);
    114     xf86VDrvMsgVerb(scrnIndex, type, DRI_MSG_VERBOSITY, format, ap);
    115     va_end(ap);
    116 }
    117 
    118 static void
    119 DRIOpenDRMCleanup(DRIEntPrivPtr pDRIEntPriv)
    120 {
    121     if (pDRIEntPriv->pLSAREA != NULL) {
    122         drmUnmap(pDRIEntPriv->pLSAREA, pDRIEntPriv->sAreaSize);
    123         pDRIEntPriv->pLSAREA = NULL;
    124     }
    125     if (pDRIEntPriv->hLSAREA != 0) {
    126         drmRmMap(pDRIEntPriv->drmFD, pDRIEntPriv->hLSAREA);
    127     }
    128     if (pDRIEntPriv->drmFD >= 0) {
    129         drmClose(pDRIEntPriv->drmFD);
    130         pDRIEntPriv->drmFD = 0;
    131     }
    132 }
    133 
    134 int
    135 DRIMasterFD(ScrnInfoPtr pScrn)
    136 {
    137     return DRI_ENT_PRIV(pScrn)->drmFD;
    138 }
    139 
    140 void *
    141 DRIMasterSareaPointer(ScrnInfoPtr pScrn)
    142 {
    143     return DRI_ENT_PRIV(pScrn)->pLSAREA;
    144 }
    145 
    146 drm_handle_t
    147 DRIMasterSareaHandle(ScrnInfoPtr pScrn)
    148 {
    149     return DRI_ENT_PRIV(pScrn)->hLSAREA;
    150 }
    151 
    152 Bool
    153 DRIOpenDRMMaster(ScrnInfoPtr pScrn,
    154                  unsigned long sAreaSize,
    155                  const char *busID, const char *drmDriverName)
    156 {
    157     drmSetVersion saveSv, sv;
    158     Bool drmWasAvailable;
    159     DRIEntPrivPtr pDRIEntPriv;
    160     DRIEntPrivRec tmp;
    161     int count;
    162     int err;
    163 
    164     if (DRIEntPrivIndex == -1)
    165         DRIEntPrivIndex = xf86AllocateEntityPrivateIndex();
    166 
    167     pDRIEntPriv = DRI_ENT_PRIV(pScrn);
    168 
    169     if (pDRIEntPriv && pDRIEntPriv->drmFD != -1)
    170         return TRUE;
    171 
    172     drmWasAvailable = drmAvailable();
    173 
    174     memset(&tmp, 0, sizeof(tmp));
    175 
    176     tmp.drmFD = -1;
    177     sv.drm_di_major = 1;
    178     sv.drm_di_minor = 1;
    179     sv.drm_dd_major = -1;
    180 
    181     saveSv = sv;
    182     count = 10;
    183     while (count--) {
    184         tmp.drmFD = drmOpen(drmDriverName, busID);
    185 
    186         if (tmp.drmFD < 0) {
    187             DRIDrvMsg(-1, X_ERROR, "[drm] drmOpen failed.\n");
    188             goto out_err;
    189         }
    190 
    191         err = drmSetInterfaceVersion(tmp.drmFD, &sv);
    192 
    193         if (err != -EPERM)
    194             break;
    195 
    196         sv = saveSv;
    197         drmClose(tmp.drmFD);
    198         tmp.drmFD = -1;
    199         usleep(100000);
    200     }
    201 
    202     if (tmp.drmFD <= 0) {
    203         DRIDrvMsg(-1, X_ERROR, "[drm] DRM was busy with another master.\n");
    204         goto out_err;
    205     }
    206 
    207     if (!drmWasAvailable) {
    208         DRIDrvMsg(-1, X_INFO,
    209                   "[drm] loaded kernel module for \"%s\" driver.\n",
    210                   drmDriverName);
    211     }
    212 
    213     if (err != 0) {
    214         sv.drm_di_major = 1;
    215         sv.drm_di_minor = 0;
    216     }
    217 
    218     DRIDrvMsg(-1, X_INFO, "[drm] DRM interface version %d.%d\n",
    219               sv.drm_di_major, sv.drm_di_minor);
    220 
    221     if (sv.drm_di_major == 1 && sv.drm_di_minor >= 1)
    222         err = 0;
    223     else
    224         err = drmSetBusid(tmp.drmFD, busID);
    225 
    226     if (err) {
    227         DRIDrvMsg(-1, X_ERROR, "[drm] Could not set DRM device bus ID.\n");
    228         goto out_err;
    229     }
    230 
    231     /*
    232      * Create a lock-containing sarea.
    233      */
    234 
    235     if (drmAddMap(tmp.drmFD, 0, sAreaSize, DRM_SHM,
    236                   DRM_CONTAINS_LOCK, &tmp.hLSAREA) < 0) {
    237         DRIDrvMsg(-1, X_INFO, "[drm] Could not create SAREA for DRM lock.\n");
    238         tmp.hLSAREA = 0;
    239         goto out_err;
    240     }
    241 
    242     if (drmMap(tmp.drmFD, tmp.hLSAREA, sAreaSize,
    243                (drmAddressPtr) (&tmp.pLSAREA)) < 0) {
    244         DRIDrvMsg(-1, X_INFO, "[drm] Mapping SAREA for DRM lock failed.\n");
    245         tmp.pLSAREA = NULL;
    246         goto out_err;
    247     }
    248 
    249     memset(tmp.pLSAREA, 0, sAreaSize);
    250 
    251     /*
    252      * Reserved contexts are handled by the first opened screen.
    253      */
    254 
    255     tmp.resOwner = NULL;
    256 
    257     if (!pDRIEntPriv)
    258         pDRIEntPriv = xnfcalloc(sizeof(*pDRIEntPriv), 1);
    259 
    260     if (!pDRIEntPriv) {
    261         DRIDrvMsg(-1, X_INFO, "[drm] Failed to allocate memory for "
    262                   "DRM device.\n");
    263         goto out_err;
    264     }
    265     *pDRIEntPriv = tmp;
    266     xf86GetEntityPrivate((pScrn)->entityList[0], DRIEntPrivIndex)->ptr =
    267         pDRIEntPriv;
    268 
    269     DRIDrvMsg(-1, X_INFO, "[drm] DRM open master succeeded.\n");
    270     return TRUE;
    271 
    272  out_err:
    273 
    274     DRIOpenDRMCleanup(&tmp);
    275     return FALSE;
    276 }
    277 
    278 static void
    279  DRIClipNotifyAllDrawables(ScreenPtr pScreen);
    280 
    281 static void
    282 dri_crtc_notify(ScreenPtr pScreen)
    283 {
    284     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    285 
    286     DRIClipNotifyAllDrawables(pScreen);
    287     xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify);
    288     xf86_crtc_notify(pScreen);
    289     pDRIPriv->xf86_crtc_notify =
    290         xf86_wrap_crtc_notify(pScreen, dri_crtc_notify);
    291 }
    292 
    293 static void
    294 drmSIGIOHandler(int interrupt, void *closure)
    295 {
    296     unsigned long key;
    297     void *value;
    298     ssize_t count;
    299     drm_ctx_t ctx;
    300     typedef void (*_drmCallback) (int, void *, void *);
    301     char buf[256];
    302     drm_context_t old;
    303     drm_context_t new;
    304     void *oldctx;
    305     void *newctx;
    306     char *pt;
    307     drmHashEntry *entry;
    308     void *hash_table;
    309 
    310     hash_table = drmGetHashTable();
    311 
    312     if (!hash_table)
    313         return;
    314     if (drmHashFirst(hash_table, &key, &value)) {
    315         entry = value;
    316         do {
    317             if ((count = read(entry->fd, buf, sizeof(buf) - 1)) > 0) {
    318                 buf[count] = '\0';
    319 
    320                 for (pt = buf; *pt != ' '; ++pt);       /* Find first space */
    321                 ++pt;
    322                 old = strtol(pt, &pt, 0);
    323                 new = strtol(pt, NULL, 0);
    324                 oldctx = drmGetContextTag(entry->fd, old);
    325                 newctx = drmGetContextTag(entry->fd, new);
    326                 ((_drmCallback) entry->f) (entry->fd, oldctx, newctx);
    327                 ctx.handle = new;
    328                 ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx);
    329             }
    330         } while (drmHashNext(hash_table, &key, &value));
    331     }
    332 }
    333 
    334 static int
    335 drmInstallSIGIOHandler(int fd, void (*f) (int, void *, void *))
    336 {
    337     drmHashEntry *entry;
    338 
    339     entry = drmGetEntry(fd);
    340     entry->f = f;
    341 
    342     return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0);
    343 }
    344 
    345 static int
    346 drmRemoveSIGIOHandler(int fd)
    347 {
    348     drmHashEntry *entry = drmGetEntry(fd);
    349 
    350     entry->f = NULL;
    351 
    352     return xf86RemoveSIGIOHandler(fd);
    353 }
    354 
    355 Bool
    356 DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD)
    357 {
    358     DRIScreenPrivPtr pDRIPriv;
    359     drm_context_t *reserved;
    360     int reserved_count;
    361     int i;
    362     DRIEntPrivPtr pDRIEntPriv;
    363     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    364     DRIContextFlags flags = 0;
    365     DRIContextPrivPtr pDRIContextPriv;
    366     static Bool drm_server_inited;
    367 
    368     /* If the DRI extension is disabled, do not initialize the DRI */
    369     if (noXFree86DRIExtension) {
    370         DRIDrvMsg(pScreen->myNum, X_WARNING,
    371                   "Direct rendering has been disabled.\n");
    372         return FALSE;
    373     }
    374 
    375     if (!xf86VGAarbiterAllowDRI(pScreen)) {
    376         DRIDrvMsg(pScreen->myNum, X_WARNING,
    377                   "Direct rendering is not supported when VGA arb is necessary for the device\n");
    378         return FALSE;
    379     }
    380 
    381 #ifdef PANORAMIX
    382     /*
    383      * If Xinerama is on, don't allow DRI to initialise.  It won't be usable
    384      * anyway.
    385      */
    386     if (!noPanoramiXExtension) {
    387         DRIDrvMsg(pScreen->myNum, X_WARNING,
    388                   "Direct rendering is not supported when Xinerama is enabled\n");
    389         return FALSE;
    390     }
    391 #endif
    392     if (drm_server_inited == FALSE) {
    393         drmSetServerInfo(&DRIDRMServerInfo);
    394         drm_server_inited = TRUE;
    395     }
    396 
    397     if (!DRIOpenDRMMaster(pScrn, pDRIInfo->SAREASize,
    398                           pDRIInfo->busIdString, pDRIInfo->drmDriverName))
    399         return FALSE;
    400 
    401     pDRIEntPriv = DRI_ENT_PRIV(pScrn);
    402 
    403     if (DRIGeneration != serverGeneration)
    404         DRIGeneration = serverGeneration;
    405 
    406     if (!dixRegisterPrivateKey(&DRIScreenPrivKeyRec, PRIVATE_SCREEN, 0))
    407         return FALSE;
    408     if (!dixRegisterPrivateKey(&DRIWindowPrivKeyRec, PRIVATE_WINDOW, 0))
    409         return FALSE;
    410 
    411     pDRIPriv = (DRIScreenPrivPtr) calloc(1, sizeof(DRIScreenPrivRec));
    412     if (!pDRIPriv) {
    413         dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
    414         return FALSE;
    415     }
    416 
    417     dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv);
    418     pDRIPriv->drmFD = pDRIEntPriv->drmFD;
    419     pDRIPriv->directRenderingSupport = TRUE;
    420     pDRIPriv->pDriverInfo = pDRIInfo;
    421     pDRIPriv->nrWindows = 0;
    422     pDRIPriv->nrWindowsVisible = 0;
    423     pDRIPriv->fullscreen = NULL;
    424 
    425     pDRIPriv->createDummyCtx = pDRIInfo->createDummyCtx;
    426     pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv;
    427 
    428     pDRIPriv->grabbedDRILock = FALSE;
    429     pDRIPriv->drmSIGIOHandlerInstalled = FALSE;
    430     *pDRMFD = pDRIPriv->drmFD;
    431 
    432     if (pDRIEntPriv->sAreaGrabbed || pDRIInfo->allocSarea) {
    433 
    434         if (drmAddMap(pDRIPriv->drmFD,
    435                       0,
    436                       pDRIPriv->pDriverInfo->SAREASize,
    437                       DRM_SHM, 0, &pDRIPriv->hSAREA) < 0) {
    438             pDRIPriv->directRenderingSupport = FALSE;
    439             dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
    440             drmClose(pDRIPriv->drmFD);
    441             DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] drmAddMap failed\n");
    442             return FALSE;
    443         }
    444         DRIDrvMsg(pScreen->myNum, X_INFO,
    445                   "[drm] added %d byte SAREA at %p\n",
    446                   (int) pDRIPriv->pDriverInfo->SAREASize, (void *) (uintptr_t) pDRIPriv->hSAREA);
    447 
    448         /* Backwards compat. */
    449         if (drmMap(pDRIPriv->drmFD,
    450                    pDRIPriv->hSAREA,
    451                    pDRIPriv->pDriverInfo->SAREASize,
    452                    (drmAddressPtr) (&pDRIPriv->pSAREA)) < 0) {
    453             pDRIPriv->directRenderingSupport = FALSE;
    454             dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
    455             drmClose(pDRIPriv->drmFD);
    456             DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] drmMap failed\n");
    457             return FALSE;
    458         }
    459         DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n",
    460                   (void *) (uintptr_t) pDRIPriv->hSAREA, pDRIPriv->pSAREA);
    461         memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize);
    462     }
    463     else {
    464         DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Using the DRM lock "
    465                   "SAREA also for drawables.\n");
    466         pDRIPriv->hSAREA = pDRIEntPriv->hLSAREA;
    467         pDRIPriv->pSAREA = (XF86DRISAREAPtr) pDRIEntPriv->pLSAREA;
    468         pDRIEntPriv->sAreaGrabbed = TRUE;
    469     }
    470 
    471     pDRIPriv->hLSAREA = pDRIEntPriv->hLSAREA;
    472     pDRIPriv->pLSAREA = pDRIEntPriv->pLSAREA;
    473 
    474     if (!pDRIPriv->pDriverInfo->dontMapFrameBuffer) {
    475         if (drmAddMap(pDRIPriv->drmFD,
    476                       (uintptr_t) pDRIPriv->pDriverInfo->
    477                       frameBufferPhysicalAddress,
    478                       pDRIPriv->pDriverInfo->frameBufferSize, DRM_FRAME_BUFFER,
    479                       0, &pDRIPriv->pDriverInfo->hFrameBuffer) < 0) {
    480             pDRIPriv->directRenderingSupport = FALSE;
    481             dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
    482             drmUnmap(pDRIPriv->pSAREA, pDRIPriv->pDriverInfo->SAREASize);
    483             drmClose(pDRIPriv->drmFD);
    484             DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] drmAddMap failed\n");
    485             return FALSE;
    486         }
    487         DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = %p\n",
    488                   (void *) (uintptr_t) pDRIPriv->pDriverInfo->hFrameBuffer);
    489     }
    490     else {
    491         DRIDrvMsg(pScreen->myNum, X_INFO,
    492                   "[drm] framebuffer mapped by ddx driver\n");
    493     }
    494 
    495     if (pDRIEntPriv->resOwner == NULL) {
    496         pDRIEntPriv->resOwner = pScreen;
    497 
    498         /* Add tags for reserved contexts */
    499         if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
    500                                                   &reserved_count))) {
    501             int r;
    502             void *tag;
    503 
    504             for (r = 0; r < reserved_count; r++) {
    505                 tag = DRICreateContextPrivFromHandle(pScreen,
    506                                                      reserved[r],
    507                                                      DRI_CONTEXT_RESERVED);
    508                 drmAddContextTag(pDRIPriv->drmFD, reserved[r], tag);
    509             }
    510             drmFreeReservedContextList(reserved);
    511             DRIDrvMsg(pScreen->myNum, X_INFO,
    512                       "[drm] added %d reserved context%s for kernel\n",
    513                       reserved_count, reserved_count > 1 ? "s" : "");
    514         }
    515     }
    516 
    517     /* validate max drawable table entry set by driver */
    518     if ((pDRIPriv->pDriverInfo->maxDrawableTableEntry <= 0) ||
    519         (pDRIPriv->pDriverInfo->maxDrawableTableEntry > SAREA_MAX_DRAWABLES)) {
    520         DRIDrvMsg(pScreen->myNum, X_ERROR,
    521                   "Invalid max drawable table size set by driver: %d\n",
    522                   pDRIPriv->pDriverInfo->maxDrawableTableEntry);
    523     }
    524 
    525     /* Initialize drawable tables (screen private and SAREA) */
    526     for (i = 0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
    527         pDRIPriv->DRIDrawables[i] = NULL;
    528         pDRIPriv->pSAREA->drawableTable[i].stamp = 0;
    529         pDRIPriv->pSAREA->drawableTable[i].flags = 0;
    530     }
    531 
    532     pDRIPriv->pLockRefCount = &pDRIEntPriv->lockRefCount;
    533     pDRIPriv->pLockingContext = &pDRIEntPriv->lockingContext;
    534 
    535     if (!pDRIEntPriv->keepFDOpen)
    536         pDRIEntPriv->keepFDOpen = pDRIInfo->keepFDOpen;
    537 
    538     pDRIEntPriv->refCount++;
    539 
    540     /* Set up flags for DRICreateContextPriv */
    541     switch (pDRIInfo->driverSwapMethod) {
    542     case DRI_KERNEL_SWAP:
    543         flags = DRI_CONTEXT_2DONLY;
    544         break;
    545     case DRI_HIDE_X_CONTEXT:
    546         flags = DRI_CONTEXT_PRESERVED;
    547         break;
    548     }
    549 
    550     if (!(pDRIContextPriv = DRICreateContextPriv(pScreen,
    551                                                  &pDRIPriv->myContext,
    552                                                  flags))) {
    553         DRIDrvMsg(pScreen->myNum, X_ERROR, "failed to create server context\n");
    554         return FALSE;
    555     }
    556     pDRIPriv->myContextPriv = pDRIContextPriv;
    557 
    558     DRIDrvMsg(pScreen->myNum, X_INFO,
    559               "X context handle = %p\n", (void *) (uintptr_t) pDRIPriv->myContext);
    560 
    561     /* Now that we have created the X server's context, we can grab the
    562      * hardware lock for the X server.
    563      */
    564     DRILock(pScreen, 0);
    565     pDRIPriv->grabbedDRILock = TRUE;
    566 
    567     /* pointers so that we can prevent memory leaks later */
    568     pDRIPriv->hiddenContextStore = NULL;
    569     pDRIPriv->partial3DContextStore = NULL;
    570 
    571     switch (pDRIInfo->driverSwapMethod) {
    572     case DRI_HIDE_X_CONTEXT:
    573         /* Server will handle 3D swaps, and hide 2D swaps from kernel.
    574          * Register server context as a preserved context.
    575          */
    576 
    577         /* allocate memory for hidden context store */
    578         pDRIPriv->hiddenContextStore
    579             = (void *) calloc(1, pDRIInfo->contextSize);
    580         if (!pDRIPriv->hiddenContextStore) {
    581             DRIDrvMsg(pScreen->myNum, X_ERROR,
    582                       "failed to allocate hidden context\n");
    583             DRIDestroyContextPriv(pDRIContextPriv);
    584             return FALSE;
    585         }
    586 
    587         /* allocate memory for partial 3D context store */
    588         pDRIPriv->partial3DContextStore
    589             = (void *) calloc(1, pDRIInfo->contextSize);
    590         if (!pDRIPriv->partial3DContextStore) {
    591             DRIDrvMsg(pScreen->myNum, X_ERROR,
    592                       "[DRI] failed to allocate partial 3D context\n");
    593             free(pDRIPriv->hiddenContextStore);
    594             DRIDestroyContextPriv(pDRIContextPriv);
    595             return FALSE;
    596         }
    597 
    598         /* save initial context store */
    599         if (pDRIInfo->SwapContext) {
    600             (*pDRIInfo->SwapContext) (pScreen,
    601                                       DRI_NO_SYNC,
    602                                       DRI_2D_CONTEXT,
    603                                       pDRIPriv->hiddenContextStore,
    604                                       DRI_NO_CONTEXT, NULL);
    605         }
    606         /* fall through */
    607 
    608     case DRI_SERVER_SWAP:
    609         /* For swap methods of DRI_SERVER_SWAP and DRI_HIDE_X_CONTEXT
    610          * setup signal handler for receiving swap requests from kernel
    611          */
    612         if (!(pDRIPriv->drmSIGIOHandlerInstalled =
    613               drmInstallSIGIOHandler(pDRIPriv->drmFD, DRISwapContext))) {
    614             DRIDrvMsg(pScreen->myNum, X_ERROR,
    615                       "[drm] failed to setup DRM signal handler\n");
    616             free(pDRIPriv->hiddenContextStore);
    617             free(pDRIPriv->partial3DContextStore);
    618             DRIDestroyContextPriv(pDRIContextPriv);
    619             return FALSE;
    620         }
    621         else {
    622             DRIDrvMsg(pScreen->myNum, X_INFO,
    623                       "[drm] installed DRM signal handler\n");
    624         }
    625 
    626     default:
    627         break;
    628     }
    629 
    630     return TRUE;
    631 }
    632 
    633 Bool
    634 DRIFinishScreenInit(ScreenPtr pScreen)
    635 {
    636     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    637     DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
    638 
    639     /* Wrap DRI support */
    640     if (pDRIInfo->wrap.WindowExposures) {
    641         pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
    642         pScreen->WindowExposures = pDRIInfo->wrap.WindowExposures;
    643     }
    644 
    645     pDRIPriv->DestroyWindow = pScreen->DestroyWindow;
    646     pScreen->DestroyWindow = DRIDestroyWindow;
    647 
    648     pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen,
    649                                                        dri_crtc_notify);
    650 
    651     if (pDRIInfo->wrap.CopyWindow) {
    652         pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
    653         pScreen->CopyWindow = pDRIInfo->wrap.CopyWindow;
    654     }
    655     if (pDRIInfo->wrap.ClipNotify) {
    656         pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
    657         pScreen->ClipNotify = pDRIInfo->wrap.ClipNotify;
    658     }
    659     if (pDRIInfo->wrap.AdjustFrame) {
    660         ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    661 
    662         pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
    663         pScrn->AdjustFrame = pDRIInfo->wrap.AdjustFrame;
    664     }
    665     pDRIPriv->wrapped = TRUE;
    666 
    667     DRIDrvMsg(pScreen->myNum, X_INFO, "[DRI] installation complete\n");
    668 
    669     return TRUE;
    670 }
    671 
    672 void
    673 DRICloseScreen(ScreenPtr pScreen)
    674 {
    675     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    676     DRIInfoPtr pDRIInfo;
    677     drm_context_t *reserved;
    678     int reserved_count;
    679     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    680     DRIEntPrivPtr pDRIEntPriv = DRI_ENT_PRIV(pScrn);
    681     Bool closeMaster;
    682 
    683     if (pDRIPriv) {
    684 
    685         pDRIInfo = pDRIPriv->pDriverInfo;
    686 
    687         if (pDRIPriv->wrapped) {
    688             /* Unwrap DRI Functions */
    689             if (pDRIInfo->wrap.WindowExposures) {
    690                 pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
    691                 pDRIPriv->wrap.WindowExposures = NULL;
    692             }
    693             if (pDRIPriv->DestroyWindow) {
    694                 pScreen->DestroyWindow = pDRIPriv->DestroyWindow;
    695                 pDRIPriv->DestroyWindow = NULL;
    696             }
    697 
    698             xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify);
    699 
    700             if (pDRIInfo->wrap.CopyWindow) {
    701                 pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
    702                 pDRIPriv->wrap.CopyWindow = NULL;
    703             }
    704             if (pDRIInfo->wrap.ClipNotify) {
    705                 pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
    706                 pDRIPriv->wrap.ClipNotify = NULL;
    707             }
    708             if (pDRIInfo->wrap.AdjustFrame) {
    709                 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
    710 
    711                 scrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
    712                 pDRIPriv->wrap.AdjustFrame = NULL;
    713             }
    714 
    715             pDRIPriv->wrapped = FALSE;
    716         }
    717 
    718         if (pDRIPriv->drmSIGIOHandlerInstalled) {
    719             if (!drmRemoveSIGIOHandler(pDRIPriv->drmFD)) {
    720                 DRIDrvMsg(pScreen->myNum, X_ERROR,
    721                           "[drm] failed to remove DRM signal handler\n");
    722             }
    723         }
    724 
    725         if (pDRIPriv->dummyCtxPriv && pDRIPriv->createDummyCtx) {
    726             DRIDestroyDummyContext(pScreen, pDRIPriv->createDummyCtxPriv);
    727         }
    728 
    729         if (!DRIDestroyContextPriv(pDRIPriv->myContextPriv)) {
    730             DRIDrvMsg(pScreen->myNum, X_ERROR,
    731                       "failed to destroy server context\n");
    732         }
    733 
    734         /* Remove tags for reserved contexts */
    735         if (pDRIEntPriv->resOwner == pScreen) {
    736             pDRIEntPriv->resOwner = NULL;
    737 
    738             if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
    739                                                       &reserved_count))) {
    740                 int i;
    741 
    742                 for (i = 0; i < reserved_count; i++) {
    743                     DRIDestroyContextPriv(drmGetContextTag(pDRIPriv->drmFD,
    744                                                            reserved[i]));
    745                 }
    746                 drmFreeReservedContextList(reserved);
    747                 DRIDrvMsg(pScreen->myNum, X_INFO,
    748                           "[drm] removed %d reserved context%s for kernel\n",
    749                           reserved_count, reserved_count > 1 ? "s" : "");
    750             }
    751         }
    752 
    753         /* Make sure signals get unblocked etc. */
    754         drmUnlock(pDRIPriv->drmFD, pDRIPriv->myContext);
    755         pDRIPriv->pLockRefCount = NULL;
    756         closeMaster = (--pDRIEntPriv->refCount == 0) &&
    757             !pDRIEntPriv->keepFDOpen;
    758         if (closeMaster || pDRIPriv->hSAREA != pDRIEntPriv->hLSAREA) {
    759             DRIDrvMsg(pScreen->myNum, X_INFO,
    760                       "[drm] unmapping %d bytes of SAREA %p at %p\n",
    761                       (int) pDRIInfo->SAREASize, (void *) (uintptr_t) pDRIPriv->hSAREA, pDRIPriv->pSAREA);
    762             if (drmUnmap(pDRIPriv->pSAREA, pDRIInfo->SAREASize)) {
    763                 DRIDrvMsg(pScreen->myNum, X_ERROR,
    764                           "[drm] unable to unmap %d bytes"
    765                           " of SAREA %p at %p\n",
    766                           (int) pDRIInfo->SAREASize,
    767                           (void *) (uintptr_t) pDRIPriv->hSAREA, pDRIPriv->pSAREA);
    768             }
    769         }
    770         else {
    771             pDRIEntPriv->sAreaGrabbed = FALSE;
    772         }
    773 
    774         if (closeMaster || (pDRIEntPriv->drmFD != pDRIPriv->drmFD)) {
    775             drmClose(pDRIPriv->drmFD);
    776             if (pDRIEntPriv->drmFD == pDRIPriv->drmFD) {
    777                 DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Closed DRM master.\n");
    778                 pDRIEntPriv->drmFD = -1;
    779             }
    780         }
    781 
    782         free(pDRIPriv);
    783         dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
    784     }
    785 }
    786 
    787 #define DRM_MSG_VERBOSITY 3
    788 
    789 static int
    790 dri_drm_debug_print(const char *format, va_list ap)
    791     _X_ATTRIBUTE_PRINTF(1,0);
    792 
    793 static int
    794 dri_drm_debug_print(const char *format, va_list ap)
    795 {
    796     xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap);
    797     return 0;
    798 }
    799 
    800 static void
    801 dri_drm_get_perms(gid_t * group, mode_t * mode)
    802 {
    803     *group = xf86ConfigDRI.group;
    804     *mode = xf86ConfigDRI.mode;
    805 }
    806 
    807 drmServerInfo DRIDRMServerInfo = {
    808     dri_drm_debug_print,
    809     xf86LoadKernelModule,
    810     dri_drm_get_perms,
    811 };
    812 
    813 Bool
    814 DRIExtensionInit(void)
    815 {
    816     if (DRIGeneration != serverGeneration) {
    817         return FALSE;
    818     }
    819 
    820     DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete,
    821                                                    "DRIDrawable");
    822     DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete,
    823                                                   "DRIContext");
    824 
    825     if (!DRIDrawablePrivResType || !DRIContextPrivResType)
    826         return FALSE;
    827 
    828     RegisterBlockAndWakeupHandlers(DRIBlockHandler, DRIWakeupHandler, NULL);
    829 
    830     return TRUE;
    831 }
    832 
    833 void
    834 DRIReset(void)
    835 {
    836     /*
    837      * This stub routine is called when the X Server recycles, resources
    838      * allocated by DRIExtensionInit need to be managed here.
    839      *
    840      * Currently this routine is a stub because all the interesting resources
    841      * are managed via the screen init process.
    842      */
    843 }
    844 
    845 Bool
    846 DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool *isCapable)
    847 {
    848     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    849 
    850     if (pDRIPriv)
    851         *isCapable = pDRIPriv->directRenderingSupport;
    852     else
    853         *isCapable = FALSE;
    854 
    855     return TRUE;
    856 }
    857 
    858 Bool
    859 DRIOpenConnection(ScreenPtr pScreen, drm_handle_t * hSAREA, char **busIdString)
    860 {
    861     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    862 
    863     *hSAREA = pDRIPriv->hSAREA;
    864     *busIdString = pDRIPriv->pDriverInfo->busIdString;
    865 
    866     return TRUE;
    867 }
    868 
    869 Bool
    870 DRIAuthConnection(ScreenPtr pScreen, drm_magic_t magic)
    871 {
    872     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    873 
    874     if (drmAuthMagic(pDRIPriv->drmFD, magic))
    875         return FALSE;
    876     return TRUE;
    877 }
    878 
    879 Bool
    880 DRICloseConnection(ScreenPtr pScreen)
    881 {
    882     return TRUE;
    883 }
    884 
    885 Bool
    886 DRIGetClientDriverName(ScreenPtr pScreen,
    887                        int *ddxDriverMajorVersion,
    888                        int *ddxDriverMinorVersion,
    889                        int *ddxDriverPatchVersion, char **clientDriverName)
    890 {
    891     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    892 
    893     *ddxDriverMajorVersion = pDRIPriv->pDriverInfo->ddxDriverMajorVersion;
    894     *ddxDriverMinorVersion = pDRIPriv->pDriverInfo->ddxDriverMinorVersion;
    895     *ddxDriverPatchVersion = pDRIPriv->pDriverInfo->ddxDriverPatchVersion;
    896     *clientDriverName = pDRIPriv->pDriverInfo->clientDriverName;
    897 
    898     return TRUE;
    899 }
    900 
    901 /* DRICreateContextPriv and DRICreateContextPrivFromHandle are helper
    902    functions that layer on drmCreateContext and drmAddContextTag.
    903 
    904    DRICreateContextPriv always creates a kernel drm_context_t and then calls
    905    DRICreateContextPrivFromHandle to create a DRIContextPriv structure for
    906    DRI tracking.  For the SIGIO handler, the drm_context_t is associated with
    907    DRIContextPrivPtr.  Any special flags are stored in the DRIContextPriv
    908    area and are passed to the kernel (if necessary).
    909 
    910    DRICreateContextPriv returns a pointer to newly allocated
    911    DRIContextPriv, and returns the kernel drm_context_t in pHWContext. */
    912 
    913 DRIContextPrivPtr
    914 DRICreateContextPriv(ScreenPtr pScreen,
    915                      drm_context_t * pHWContext, DRIContextFlags flags)
    916 {
    917     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    918 
    919     if (drmCreateContext(pDRIPriv->drmFD, pHWContext)) {
    920         return NULL;
    921     }
    922 
    923     return DRICreateContextPrivFromHandle(pScreen, *pHWContext, flags);
    924 }
    925 
    926 DRIContextPrivPtr
    927 DRICreateContextPrivFromHandle(ScreenPtr pScreen,
    928                                drm_context_t hHWContext, DRIContextFlags flags)
    929 {
    930     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
    931     DRIContextPrivPtr pDRIContextPriv;
    932     int contextPrivSize;
    933 
    934     contextPrivSize = sizeof(DRIContextPrivRec) +
    935         pDRIPriv->pDriverInfo->contextSize;
    936     if (!(pDRIContextPriv = calloc(1, contextPrivSize))) {
    937         return NULL;
    938     }
    939     pDRIContextPriv->pContextStore = (void *) (pDRIContextPriv + 1);
    940 
    941     drmAddContextTag(pDRIPriv->drmFD, hHWContext, pDRIContextPriv);
    942 
    943     pDRIContextPriv->hwContext = hHWContext;
    944     pDRIContextPriv->pScreen = pScreen;
    945     pDRIContextPriv->flags = flags;
    946     pDRIContextPriv->valid3D = FALSE;
    947 
    948     if (flags & DRI_CONTEXT_2DONLY) {
    949         if (drmSetContextFlags(pDRIPriv->drmFD, hHWContext, DRM_CONTEXT_2DONLY)) {
    950             DRIDrvMsg(pScreen->myNum, X_ERROR,
    951                       "[drm] failed to set 2D context flag\n");
    952             DRIDestroyContextPriv(pDRIContextPriv);
    953             return NULL;
    954         }
    955     }
    956     if (flags & DRI_CONTEXT_PRESERVED) {
    957         if (drmSetContextFlags(pDRIPriv->drmFD,
    958                                hHWContext, DRM_CONTEXT_PRESERVED)) {
    959             DRIDrvMsg(pScreen->myNum, X_ERROR,
    960                       "[drm] failed to set preserved flag\n");
    961             DRIDestroyContextPriv(pDRIContextPriv);
    962             return NULL;
    963         }
    964     }
    965     return pDRIContextPriv;
    966 }
    967 
    968 Bool
    969 DRIDestroyContextPriv(DRIContextPrivPtr pDRIContextPriv)
    970 {
    971     DRIScreenPrivPtr pDRIPriv;
    972 
    973     if (!pDRIContextPriv)
    974         return TRUE;
    975 
    976     pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen);
    977 
    978     if (!(pDRIContextPriv->flags & DRI_CONTEXT_RESERVED)) {
    979         /* Don't delete reserved contexts from
    980            kernel area -- the kernel manages its
    981            reserved contexts itself. */
    982         if (drmDestroyContext(pDRIPriv->drmFD, pDRIContextPriv->hwContext))
    983             return FALSE;
    984     }
    985 
    986     /* Remove the tag last to prevent a race
    987        condition where the context has pending
    988        buffers.  The context can't be re-used
    989        while in this thread, but buffers can be
    990        dispatched asynchronously. */
    991     drmDelContextTag(pDRIPriv->drmFD, pDRIContextPriv->hwContext);
    992     free(pDRIContextPriv);
    993     return TRUE;
    994 }
    995 
    996 static Bool
    997 DRICreateDummyContext(ScreenPtr pScreen, Bool needCtxPriv)
    998 {
    999     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1000     DRIContextPrivPtr pDRIContextPriv;
   1001     void *contextStore;
   1002 
   1003     if (!(pDRIContextPriv =
   1004           DRICreateContextPriv(pScreen, &pDRIPriv->pSAREA->dummy_context, 0))) {
   1005         return FALSE;
   1006     }
   1007 
   1008     contextStore = DRIGetContextStore(pDRIContextPriv);
   1009     if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) {
   1010         if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, NULL,
   1011                                                   pDRIPriv->pSAREA->
   1012                                                   dummy_context, NULL,
   1013                                                   (DRIContextType) (long)
   1014                                                   contextStore)) {
   1015             DRIDestroyContextPriv(pDRIContextPriv);
   1016             return FALSE;
   1017         }
   1018     }
   1019 
   1020     pDRIPriv->dummyCtxPriv = pDRIContextPriv;
   1021     return TRUE;
   1022 }
   1023 
   1024 static void
   1025 DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv)
   1026 {
   1027     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1028     DRIContextPrivPtr pDRIContextPriv = pDRIPriv->dummyCtxPriv;
   1029     void *contextStore;
   1030 
   1031     if (!pDRIContextPriv)
   1032         return;
   1033     if (pDRIPriv->pDriverInfo->DestroyContext && hasCtxPriv) {
   1034         contextStore = DRIGetContextStore(pDRIContextPriv);
   1035         pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
   1036                                               pDRIContextPriv->hwContext,
   1037                                               (DRIContextType) (long)
   1038                                               contextStore);
   1039     }
   1040 
   1041     DRIDestroyContextPriv(pDRIPriv->dummyCtxPriv);
   1042     pDRIPriv->dummyCtxPriv = NULL;
   1043 }
   1044 
   1045 Bool
   1046 DRICreateContext(ScreenPtr pScreen, VisualPtr visual,
   1047                  XID context, drm_context_t * pHWContext)
   1048 {
   1049     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1050     DRIContextPrivPtr pDRIContextPriv;
   1051     void *contextStore;
   1052 
   1053     if (pDRIPriv->createDummyCtx && !pDRIPriv->dummyCtxPriv) {
   1054         if (!DRICreateDummyContext(pScreen, pDRIPriv->createDummyCtxPriv)) {
   1055             DRIDrvMsg(pScreen->myNum, X_INFO,
   1056                       "[drm] Could not create dummy context\n");
   1057             return FALSE;
   1058         }
   1059     }
   1060 
   1061     if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) {
   1062         return FALSE;
   1063     }
   1064 
   1065     contextStore = DRIGetContextStore(pDRIContextPriv);
   1066     if (pDRIPriv->pDriverInfo->CreateContext) {
   1067         if (!((*pDRIPriv->pDriverInfo->CreateContext) (pScreen, NULL,
   1068                                                        *pHWContext, NULL,
   1069                                                        (DRIContextType) (long)
   1070                                                        contextStore))) {
   1071             DRIDestroyContextPriv(pDRIContextPriv);
   1072             return FALSE;
   1073         }
   1074     }
   1075 
   1076     /* track this in case the client dies before cleanup */
   1077     if (!AddResource(context, DRIContextPrivResType, (void *) pDRIContextPriv))
   1078         return FALSE;
   1079 
   1080     return TRUE;
   1081 }
   1082 
   1083 Bool
   1084 DRIDestroyContext(ScreenPtr pScreen, XID context)
   1085 {
   1086     FreeResourceByType(context, DRIContextPrivResType, FALSE);
   1087 
   1088     return TRUE;
   1089 }
   1090 
   1091 /* DRIContextPrivDelete is called by the resource manager. */
   1092 Bool
   1093 DRIContextPrivDelete(void *pResource, XID id)
   1094 {
   1095     DRIContextPrivPtr pDRIContextPriv = (DRIContextPrivPtr) pResource;
   1096     DRIScreenPrivPtr pDRIPriv;
   1097     void *contextStore;
   1098 
   1099     pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen);
   1100     if (pDRIPriv->pDriverInfo->DestroyContext) {
   1101         contextStore = DRIGetContextStore(pDRIContextPriv);
   1102         pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
   1103                                               pDRIContextPriv->hwContext,
   1104                                               (DRIContextType) (long)
   1105                                               contextStore);
   1106     }
   1107     return DRIDestroyContextPriv(pDRIContextPriv);
   1108 }
   1109 
   1110 /* This walks the drawable timestamp array and invalidates all of them
   1111  * in the case of transition from private to shared backbuffers.  It's
   1112  * not necessary for correctness, because DRIClipNotify gets called in
   1113  * time to prevent any conflict, but the transition from
   1114  * shared->private is sometimes missed if we don't do this.
   1115  */
   1116 static void
   1117 DRIClipNotifyAllDrawables(ScreenPtr pScreen)
   1118 {
   1119     int i;
   1120     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1121 
   1122     for (i = 0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
   1123         pDRIPriv->pSAREA->drawableTable[i].stamp = DRIDrawableValidationStamp++;
   1124     }
   1125 }
   1126 
   1127 static void
   1128 DRITransitionToSharedBuffers(ScreenPtr pScreen)
   1129 {
   1130     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1131     DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
   1132 
   1133     DRIClipNotifyAllDrawables(pScreen);
   1134 
   1135     if (pDRIInfo->TransitionSingleToMulti3D)
   1136         pDRIInfo->TransitionSingleToMulti3D(pScreen);
   1137 }
   1138 
   1139 static void
   1140 DRITransitionToPrivateBuffers(ScreenPtr pScreen)
   1141 {
   1142     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1143     DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
   1144 
   1145     DRIClipNotifyAllDrawables(pScreen);
   1146 
   1147     if (pDRIInfo->TransitionMultiToSingle3D)
   1148         pDRIInfo->TransitionMultiToSingle3D(pScreen);
   1149 }
   1150 
   1151 static void
   1152 DRITransitionTo3d(ScreenPtr pScreen)
   1153 {
   1154     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1155     DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
   1156 
   1157     DRIClipNotifyAllDrawables(pScreen);
   1158 
   1159     if (pDRIInfo->TransitionTo3d)
   1160         pDRIInfo->TransitionTo3d(pScreen);
   1161 }
   1162 
   1163 static void
   1164 DRITransitionTo2d(ScreenPtr pScreen)
   1165 {
   1166     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1167     DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
   1168 
   1169     DRIClipNotifyAllDrawables(pScreen);
   1170 
   1171     if (pDRIInfo->TransitionTo2d)
   1172         pDRIInfo->TransitionTo2d(pScreen);
   1173 }
   1174 
   1175 static int
   1176 DRIDCNTreeTraversal(WindowPtr pWin, void *data)
   1177 {
   1178     DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
   1179 
   1180     if (pDRIDrawablePriv) {
   1181         ScreenPtr pScreen = pWin->drawable.pScreen;
   1182         DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1183 
   1184         if (RegionNumRects(&pWin->clipList) > 0) {
   1185             WindowPtr *pDRIWindows = (WindowPtr *) data;
   1186             int i = 0;
   1187 
   1188             while (pDRIWindows[i])
   1189                 i++;
   1190 
   1191             pDRIWindows[i] = pWin;
   1192 
   1193             pDRIPriv->nrWalked++;
   1194         }
   1195 
   1196         if (pDRIPriv->nrWindows == pDRIPriv->nrWalked)
   1197             return WT_STOPWALKING;
   1198     }
   1199 
   1200     return WT_WALKCHILDREN;
   1201 }
   1202 
   1203 static void
   1204 DRIDriverClipNotify(ScreenPtr pScreen)
   1205 {
   1206     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1207 
   1208     if (pDRIPriv->pDriverInfo->ClipNotify) {
   1209         WindowPtr *pDRIWindows = calloc(sizeof(WindowPtr), pDRIPriv->nrWindows);
   1210         DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
   1211 
   1212         if (pDRIPriv->nrWindows > 0) {
   1213             pDRIPriv->nrWalked = 0;
   1214             TraverseTree(pScreen->root, DRIDCNTreeTraversal,
   1215                          (void *) pDRIWindows);
   1216         }
   1217 
   1218         pDRIInfo->ClipNotify(pScreen, pDRIWindows, pDRIPriv->nrWindows);
   1219 
   1220         free(pDRIWindows);
   1221     }
   1222 }
   1223 
   1224 static void
   1225 DRIIncreaseNumberVisible(ScreenPtr pScreen)
   1226 {
   1227     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1228 
   1229     switch (++pDRIPriv->nrWindowsVisible) {
   1230     case 1:
   1231         DRITransitionTo3d(pScreen);
   1232         break;
   1233     case 2:
   1234         DRITransitionToSharedBuffers(pScreen);
   1235         break;
   1236     default:
   1237         break;
   1238     }
   1239 
   1240     DRIDriverClipNotify(pScreen);
   1241 }
   1242 
   1243 static void
   1244 DRIDecreaseNumberVisible(ScreenPtr pScreen)
   1245 {
   1246     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1247 
   1248     switch (--pDRIPriv->nrWindowsVisible) {
   1249     case 0:
   1250         DRITransitionTo2d(pScreen);
   1251         break;
   1252     case 1:
   1253         DRITransitionToPrivateBuffers(pScreen);
   1254         break;
   1255     default:
   1256         break;
   1257     }
   1258 
   1259     DRIDriverClipNotify(pScreen);
   1260 }
   1261 
   1262 Bool
   1263 DRICreateDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable,
   1264                   drm_drawable_t * hHWDrawable)
   1265 {
   1266     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1267     DRIDrawablePrivPtr pDRIDrawablePriv;
   1268     WindowPtr pWin;
   1269 
   1270     if (pDrawable->type == DRAWABLE_WINDOW) {
   1271         pWin = (WindowPtr) pDrawable;
   1272         if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
   1273             pDRIDrawablePriv->refCount++;
   1274 
   1275             if (!pDRIDrawablePriv->hwDrawable) {
   1276                 drmCreateDrawable(pDRIPriv->drmFD,
   1277                                   &pDRIDrawablePriv->hwDrawable);
   1278             }
   1279         }
   1280         else {
   1281             /* allocate a DRI Window Private record */
   1282             if (!(pDRIDrawablePriv = malloc(sizeof(DRIDrawablePrivRec)))) {
   1283                 return FALSE;
   1284             }
   1285 
   1286             /* Only create a drm_drawable_t once */
   1287             if (drmCreateDrawable(pDRIPriv->drmFD,
   1288                                   &pDRIDrawablePriv->hwDrawable)) {
   1289                 free(pDRIDrawablePriv);
   1290                 return FALSE;
   1291             }
   1292 
   1293             /* add it to the list of DRI drawables for this screen */
   1294             pDRIDrawablePriv->pScreen = pScreen;
   1295             pDRIDrawablePriv->refCount = 1;
   1296             pDRIDrawablePriv->drawableIndex = -1;
   1297             pDRIDrawablePriv->nrects = RegionNumRects(&pWin->clipList);
   1298 
   1299             /* save private off of preallocated index */
   1300             dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey,
   1301                           pDRIDrawablePriv);
   1302             pDRIPriv->nrWindows++;
   1303 
   1304             if (pDRIDrawablePriv->nrects)
   1305                 DRIIncreaseNumberVisible(pScreen);
   1306         }
   1307 
   1308         /* track this in case the client dies */
   1309         if (!AddResource(FakeClientID(client->index), DRIDrawablePrivResType,
   1310                          (void *) (intptr_t) pDrawable->id))
   1311             return FALSE;
   1312 
   1313         if (pDRIDrawablePriv->hwDrawable) {
   1314             drmUpdateDrawableInfo(pDRIPriv->drmFD,
   1315                                   pDRIDrawablePriv->hwDrawable,
   1316                                   DRM_DRAWABLE_CLIPRECTS,
   1317                                   RegionNumRects(&pWin->clipList),
   1318                                   RegionRects(&pWin->clipList));
   1319             *hHWDrawable = pDRIDrawablePriv->hwDrawable;
   1320         }
   1321     }
   1322     else if (pDrawable->type != DRAWABLE_PIXMAP) {      /* PBuffer */
   1323         /* NOT_DONE */
   1324         return FALSE;
   1325     }
   1326 
   1327     return TRUE;
   1328 }
   1329 
   1330 static void
   1331 DRIDrawablePrivDestroy(WindowPtr pWin)
   1332 {
   1333     DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
   1334     ScreenPtr pScreen;
   1335     DRIScreenPrivPtr pDRIPriv;
   1336 
   1337     if (!pDRIDrawablePriv)
   1338         return;
   1339 
   1340     pScreen = pWin->drawable.pScreen;
   1341     pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1342 
   1343     if (pDRIDrawablePriv->drawableIndex != -1) {
   1344         /* bump stamp to force outstanding 3D requests to resync */
   1345         pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
   1346             = DRIDrawableValidationStamp++;
   1347 
   1348         /* release drawable table entry */
   1349         pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL;
   1350     }
   1351 
   1352     pDRIPriv->nrWindows--;
   1353 
   1354     if (pDRIDrawablePriv->nrects)
   1355         DRIDecreaseNumberVisible(pScreen);
   1356 
   1357     drmDestroyDrawable(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable);
   1358 
   1359     free(pDRIDrawablePriv);
   1360     dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL);
   1361 }
   1362 
   1363 static Bool
   1364 DRIDestroyDrawableCB(void *value, XID id, void *data)
   1365 {
   1366     if (value == data) {
   1367         /* This calls back DRIDrawablePrivDelete which frees private area */
   1368         FreeResourceByType(id, DRIDrawablePrivResType, FALSE);
   1369 
   1370         return TRUE;
   1371     }
   1372 
   1373     return FALSE;
   1374 }
   1375 
   1376 Bool
   1377 DRIDestroyDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable)
   1378 {
   1379     if (pDrawable->type == DRAWABLE_WINDOW) {
   1380         LookupClientResourceComplex(client, DRIDrawablePrivResType,
   1381                                     DRIDestroyDrawableCB,
   1382                                     (void *) (intptr_t) pDrawable->id);
   1383     }
   1384     else {                      /* pixmap (or for GLX 1.3, a PBuffer) */
   1385         /* NOT_DONE */
   1386         return FALSE;
   1387     }
   1388 
   1389     return TRUE;
   1390 }
   1391 
   1392 Bool
   1393 DRIDrawablePrivDelete(void *pResource, XID id)
   1394 {
   1395     WindowPtr pWin;
   1396     int rc;
   1397 
   1398     /* For DRIDrawablePrivResType, the XID is the client's fake ID. The
   1399      * important XID is the value in pResource. */
   1400     id = (XID) (intptr_t) pResource;
   1401     rc = dixLookupWindow(&pWin, id, serverClient, DixGetAttrAccess);
   1402 
   1403     if (rc == Success) {
   1404         DRIDrawablePrivPtr pDRIDrwPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
   1405 
   1406         if (!pDRIDrwPriv)
   1407             return FALSE;
   1408 
   1409         if (--pDRIDrwPriv->refCount == 0)
   1410             DRIDrawablePrivDestroy(pWin);
   1411 
   1412         return TRUE;
   1413     }
   1414     else {                      /* pixmap (or for GLX 1.3, a PBuffer) */
   1415         /* NOT_DONE */
   1416         return FALSE;
   1417     }
   1418 }
   1419 
   1420 Bool
   1421 DRIGetDrawableInfo(ScreenPtr pScreen,
   1422                    DrawablePtr pDrawable,
   1423                    unsigned int *index,
   1424                    unsigned int *stamp,
   1425                    int *X,
   1426                    int *Y,
   1427                    int *W,
   1428                    int *H,
   1429                    int *numClipRects,
   1430                    drm_clip_rect_t ** pClipRects,
   1431                    int *backX,
   1432                    int *backY,
   1433                    int *numBackClipRects, drm_clip_rect_t ** pBackClipRects)
   1434 {
   1435     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1436     DRIDrawablePrivPtr pDRIDrawablePriv, pOldDrawPriv;
   1437     WindowPtr pWin, pOldWin;
   1438     int i;
   1439 
   1440 #if 0
   1441     printf("maxDrawableTableEntry = %d\n",
   1442            pDRIPriv->pDriverInfo->maxDrawableTableEntry);
   1443 #endif
   1444 
   1445     if (pDrawable->type == DRAWABLE_WINDOW) {
   1446         pWin = (WindowPtr) pDrawable;
   1447         if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
   1448 
   1449             /* Manage drawable table */
   1450             if (pDRIDrawablePriv->drawableIndex == -1) {        /* load SAREA table */
   1451 
   1452                 /* Search table for empty entry */
   1453                 i = 0;
   1454                 while (i < pDRIPriv->pDriverInfo->maxDrawableTableEntry) {
   1455                     if (!(pDRIPriv->DRIDrawables[i])) {
   1456                         pDRIPriv->DRIDrawables[i] = pDrawable;
   1457                         pDRIDrawablePriv->drawableIndex = i;
   1458                         pDRIPriv->pSAREA->drawableTable[i].stamp =
   1459                             DRIDrawableValidationStamp++;
   1460                         break;
   1461                     }
   1462                     i++;
   1463                 }
   1464 
   1465                 /* Search table for oldest entry */
   1466                 if (i == pDRIPriv->pDriverInfo->maxDrawableTableEntry) {
   1467                     unsigned int oldestStamp = ~0;
   1468                     int oldestIndex = 0;
   1469 
   1470                     i = pDRIPriv->pDriverInfo->maxDrawableTableEntry;
   1471                     while (i--) {
   1472                         if (pDRIPriv->pSAREA->drawableTable[i].stamp <
   1473                             oldestStamp) {
   1474                             oldestIndex = i;
   1475                             oldestStamp =
   1476                                 pDRIPriv->pSAREA->drawableTable[i].stamp;
   1477                         }
   1478                     }
   1479                     pDRIDrawablePriv->drawableIndex = oldestIndex;
   1480 
   1481                     /* release oldest drawable table entry */
   1482                     pOldWin = (WindowPtr) pDRIPriv->DRIDrawables[oldestIndex];
   1483                     pOldDrawPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pOldWin);
   1484                     pOldDrawPriv->drawableIndex = -1;
   1485 
   1486                     /* claim drawable table entry */
   1487                     pDRIPriv->DRIDrawables[oldestIndex] = pDrawable;
   1488 
   1489                     /* validate SAREA entry */
   1490                     pDRIPriv->pSAREA->drawableTable[oldestIndex].stamp =
   1491                         DRIDrawableValidationStamp++;
   1492 
   1493                     /* check for stamp wrap around */
   1494                     if (oldestStamp > DRIDrawableValidationStamp) {
   1495 
   1496                         /* walk SAREA table and invalidate all drawables */
   1497                         for (i = 0;
   1498                              i < pDRIPriv->pDriverInfo->maxDrawableTableEntry;
   1499                              i++) {
   1500                             pDRIPriv->pSAREA->drawableTable[i].stamp =
   1501                                 DRIDrawableValidationStamp++;
   1502                         }
   1503                     }
   1504                 }
   1505 
   1506                 /* If the driver wants to be notified when the index is
   1507                  * set for a drawable, let it know now.
   1508                  */
   1509                 if (pDRIPriv->pDriverInfo->SetDrawableIndex)
   1510                     pDRIPriv->pDriverInfo->SetDrawableIndex(pWin,
   1511                                                             pDRIDrawablePriv->
   1512                                                             drawableIndex);
   1513 
   1514                 /* reinit drawable ID if window is visible */
   1515                 if ((pWin->viewable) &&
   1516                     (pDRIPriv->pDriverInfo->bufferRequests != DRI_NO_WINDOWS)) {
   1517                     (*pDRIPriv->pDriverInfo->InitBuffers) (pWin,
   1518                                                            &pWin->clipList,
   1519                                                            pDRIDrawablePriv->
   1520                                                            drawableIndex);
   1521                 }
   1522             }
   1523 
   1524             *index = pDRIDrawablePriv->drawableIndex;
   1525             *stamp = pDRIPriv->pSAREA->drawableTable[*index].stamp;
   1526             *X = (int) (pWin->drawable.x);
   1527             *Y = (int) (pWin->drawable.y);
   1528             *W = (int) (pWin->drawable.width);
   1529             *H = (int) (pWin->drawable.height);
   1530             *numClipRects = RegionNumRects(&pWin->clipList);
   1531             *pClipRects = (drm_clip_rect_t *) RegionRects(&pWin->clipList);
   1532 
   1533             if (!*numClipRects && pDRIPriv->fullscreen) {
   1534                 /* use fake full-screen clip rect */
   1535                 pDRIPriv->fullscreen_rect.x1 = *X;
   1536                 pDRIPriv->fullscreen_rect.y1 = *Y;
   1537                 pDRIPriv->fullscreen_rect.x2 = *X + *W;
   1538                 pDRIPriv->fullscreen_rect.y2 = *Y + *H;
   1539 
   1540                 *numClipRects = 1;
   1541                 *pClipRects = &pDRIPriv->fullscreen_rect;
   1542             }
   1543 
   1544             *backX = *X;
   1545             *backY = *Y;
   1546 
   1547             if (pDRIPriv->nrWindowsVisible == 1 && *numClipRects) {
   1548                 /* Use a single cliprect. */
   1549 
   1550                 int x0 = *X;
   1551                 int y0 = *Y;
   1552                 int x1 = x0 + *W;
   1553                 int y1 = y0 + *H;
   1554 
   1555                 if (x0 < 0)
   1556                     x0 = 0;
   1557                 if (y0 < 0)
   1558                     y0 = 0;
   1559                 if (x1 > pScreen->width)
   1560                     x1 = pScreen->width;
   1561                 if (y1 > pScreen->height)
   1562                     y1 = pScreen->height;
   1563 
   1564                 if (y0 >= y1 || x0 >= x1) {
   1565                     *numBackClipRects = 0;
   1566                     *pBackClipRects = NULL;
   1567                 }
   1568                 else {
   1569                     pDRIPriv->private_buffer_rect.x1 = x0;
   1570                     pDRIPriv->private_buffer_rect.y1 = y0;
   1571                     pDRIPriv->private_buffer_rect.x2 = x1;
   1572                     pDRIPriv->private_buffer_rect.y2 = y1;
   1573 
   1574                     *numBackClipRects = 1;
   1575                     *pBackClipRects = &(pDRIPriv->private_buffer_rect);
   1576                 }
   1577             }
   1578             else {
   1579                 /* Use the frontbuffer cliprects for back buffers.  */
   1580                 *numBackClipRects = 0;
   1581                 *pBackClipRects = 0;
   1582             }
   1583         }
   1584         else {
   1585             /* Not a DRIDrawable */
   1586             return FALSE;
   1587         }
   1588     }
   1589     else {                      /* pixmap (or for GLX 1.3, a PBuffer) */
   1590         /* NOT_DONE */
   1591         return FALSE;
   1592     }
   1593 
   1594     return TRUE;
   1595 }
   1596 
   1597 Bool
   1598 DRIGetDeviceInfo(ScreenPtr pScreen,
   1599                  drm_handle_t * hFrameBuffer,
   1600                  int *fbOrigin,
   1601                  int *fbSize,
   1602                  int *fbStride, int *devPrivateSize, void **pDevPrivate)
   1603 {
   1604     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1605 
   1606     *hFrameBuffer = pDRIPriv->pDriverInfo->hFrameBuffer;
   1607     *fbOrigin = 0;
   1608     *fbSize = pDRIPriv->pDriverInfo->frameBufferSize;
   1609     *fbStride = pDRIPriv->pDriverInfo->frameBufferStride;
   1610     *devPrivateSize = pDRIPriv->pDriverInfo->devPrivateSize;
   1611     *pDevPrivate = pDRIPriv->pDriverInfo->devPrivate;
   1612 
   1613     return TRUE;
   1614 }
   1615 
   1616 DRIInfoPtr
   1617 DRICreateInfoRec(void)
   1618 {
   1619     DRIInfoPtr inforec = (DRIInfoPtr) calloc(1, sizeof(DRIInfoRec));
   1620 
   1621     if (!inforec)
   1622         return NULL;
   1623 
   1624     /* Initialize defaults */
   1625     inforec->busIdString = NULL;
   1626 
   1627     /* Wrapped function defaults */
   1628     inforec->wrap.WakeupHandler = DRIDoWakeupHandler;
   1629     inforec->wrap.BlockHandler = DRIDoBlockHandler;
   1630     inforec->wrap.WindowExposures = DRIWindowExposures;
   1631     inforec->wrap.CopyWindow = DRICopyWindow;
   1632     inforec->wrap.ClipNotify = DRIClipNotify;
   1633     inforec->wrap.AdjustFrame = DRIAdjustFrame;
   1634 
   1635     inforec->TransitionTo2d = 0;
   1636     inforec->TransitionTo3d = 0;
   1637     inforec->SetDrawableIndex = 0;
   1638 
   1639     return inforec;
   1640 }
   1641 
   1642 void
   1643 DRIDestroyInfoRec(DRIInfoPtr DRIInfo)
   1644 {
   1645     free(DRIInfo->busIdString);
   1646     free((char *) DRIInfo);
   1647 }
   1648 
   1649 void
   1650 DRIWakeupHandler(void *wakeupData, int result)
   1651 {
   1652     int i;
   1653 
   1654     for (i = 0; i < screenInfo.numScreens; i++) {
   1655         ScreenPtr pScreen = screenInfo.screens[i];
   1656         DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1657 
   1658         if (pDRIPriv && pDRIPriv->pDriverInfo->wrap.WakeupHandler)
   1659             (*pDRIPriv->pDriverInfo->wrap.WakeupHandler) (pScreen, result);
   1660     }
   1661 }
   1662 
   1663 void
   1664 DRIBlockHandler(void *blockData, void *pTimeout)
   1665 {
   1666     int i;
   1667 
   1668     for (i = 0; i < screenInfo.numScreens; i++) {
   1669         ScreenPtr pScreen = screenInfo.screens[i];
   1670         DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1671 
   1672         if (pDRIPriv && pDRIPriv->pDriverInfo->wrap.BlockHandler)
   1673             (*pDRIPriv->pDriverInfo->wrap.BlockHandler) (pScreen, pTimeout);
   1674     }
   1675 }
   1676 
   1677 void
   1678 DRIDoWakeupHandler(ScreenPtr pScreen, int result)
   1679 {
   1680     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1681 
   1682     DRILock(pScreen, 0);
   1683     if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
   1684         /* hide X context by swapping 2D component here */
   1685         (*pDRIPriv->pDriverInfo->SwapContext) (pScreen,
   1686                                                DRI_3D_SYNC,
   1687                                                DRI_2D_CONTEXT,
   1688                                                pDRIPriv->partial3DContextStore,
   1689                                                DRI_2D_CONTEXT,
   1690                                                pDRIPriv->hiddenContextStore);
   1691     }
   1692 }
   1693 
   1694 void
   1695 DRIDoBlockHandler(ScreenPtr pScreen, void *timeout)
   1696 {
   1697     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1698 
   1699     if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
   1700         /* hide X context by swapping 2D component here */
   1701         (*pDRIPriv->pDriverInfo->SwapContext) (pScreen,
   1702                                                DRI_2D_SYNC,
   1703                                                DRI_NO_CONTEXT,
   1704                                                NULL,
   1705                                                DRI_2D_CONTEXT,
   1706                                                pDRIPriv->partial3DContextStore);
   1707     }
   1708 
   1709     if (pDRIPriv->windowsTouched)
   1710         DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1);
   1711     pDRIPriv->windowsTouched = FALSE;
   1712 
   1713     DRIUnlock(pScreen);
   1714 }
   1715 
   1716 void
   1717 DRISwapContext(int drmFD, void *oldctx, void *newctx)
   1718 {
   1719     DRIContextPrivPtr oldContext = (DRIContextPrivPtr) oldctx;
   1720     DRIContextPrivPtr newContext = (DRIContextPrivPtr) newctx;
   1721     ScreenPtr pScreen = newContext->pScreen;
   1722     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1723     void *oldContextStore = NULL;
   1724     DRIContextType oldContextType;
   1725     void *newContextStore = NULL;
   1726     DRIContextType newContextType;
   1727     DRISyncType syncType;
   1728 
   1729 #ifdef DEBUG
   1730     static int count = 0;
   1731 
   1732     if (!newContext) {
   1733         DRIDrvMsg(pScreen->myNum, X_ERROR,
   1734                   "[DRI] Context Switch Error: oldContext=%p, newContext=%p\n",
   1735                   oldContext, newContext);
   1736         return;
   1737     }
   1738 
   1739     /* useful for debugging, just print out after n context switches */
   1740     if (!count || !(count % 1)) {
   1741         DRIDrvMsg(pScreen->myNum, X_INFO,
   1742                   "[DRI] Context switch %5d from %p/0x%08x (%d)\n",
   1743                   count,
   1744                   oldContext,
   1745                   oldContext ? oldContext->flags : 0,
   1746                   oldContext ? oldContext->hwContext : -1);
   1747         DRIDrvMsg(pScreen->myNum, X_INFO,
   1748                   "[DRI] Context switch %5d to   %p/0x%08x (%d)\n",
   1749                   count,
   1750                   newContext,
   1751                   newContext ? newContext->flags : 0,
   1752                   newContext ? newContext->hwContext : -1);
   1753     }
   1754     ++count;
   1755 #endif
   1756 
   1757     if (!pDRIPriv->pDriverInfo->SwapContext) {
   1758         DRIDrvMsg(pScreen->myNum, X_ERROR,
   1759                   "[DRI] DDX driver missing context swap call back\n");
   1760         return;
   1761     }
   1762 
   1763     if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
   1764 
   1765         /* only 3D contexts are swapped in this case */
   1766         if (oldContext) {
   1767             oldContextStore = DRIGetContextStore(oldContext);
   1768             oldContext->valid3D = TRUE;
   1769             oldContextType = DRI_3D_CONTEXT;
   1770         }
   1771         else {
   1772             oldContextType = DRI_NO_CONTEXT;
   1773         }
   1774         newContextStore = DRIGetContextStore(newContext);
   1775         if ((newContext->valid3D) &&
   1776             (newContext->hwContext != pDRIPriv->myContext)) {
   1777             newContextType = DRI_3D_CONTEXT;
   1778         }
   1779         else {
   1780             newContextType = DRI_2D_CONTEXT;
   1781         }
   1782         syncType = DRI_3D_SYNC;
   1783     }
   1784     else {                      /* default: driverSwapMethod == DRI_SERVER_SWAP */
   1785 
   1786         /* optimize 2D context swaps */
   1787 
   1788         if (newContext->flags & DRI_CONTEXT_2DONLY) {
   1789             /* go from 3D context to 2D context and only save 2D
   1790              * subset of 3D state
   1791              */
   1792             oldContextStore = DRIGetContextStore(oldContext);
   1793             oldContextType = DRI_2D_CONTEXT;
   1794             newContextStore = DRIGetContextStore(newContext);
   1795             newContextType = DRI_2D_CONTEXT;
   1796             syncType = DRI_3D_SYNC;
   1797             pDRIPriv->lastPartial3DContext = oldContext;
   1798         }
   1799         else if (oldContext->flags & DRI_CONTEXT_2DONLY) {
   1800             if (pDRIPriv->lastPartial3DContext == newContext) {
   1801                 /* go from 2D context back to previous 3D context and
   1802                  * only restore 2D subset of previous 3D state
   1803                  */
   1804                 oldContextStore = DRIGetContextStore(oldContext);
   1805                 oldContextType = DRI_2D_CONTEXT;
   1806                 newContextStore = DRIGetContextStore(newContext);
   1807                 newContextType = DRI_2D_CONTEXT;
   1808                 syncType = DRI_2D_SYNC;
   1809             }
   1810             else {
   1811                 /* go from 2D context to a different 3D context */
   1812 
   1813                 /* call DDX driver to do partial restore */
   1814                 oldContextStore = DRIGetContextStore(oldContext);
   1815                 newContextStore =
   1816                     DRIGetContextStore(pDRIPriv->lastPartial3DContext);
   1817                 (*pDRIPriv->pDriverInfo->SwapContext) (pScreen,
   1818                                                        DRI_2D_SYNC,
   1819                                                        DRI_2D_CONTEXT,
   1820                                                        oldContextStore,
   1821                                                        DRI_2D_CONTEXT,
   1822                                                        newContextStore);
   1823 
   1824                 /* now setup for a complete 3D swap */
   1825                 oldContextStore = newContextStore;
   1826                 oldContext->valid3D = TRUE;
   1827                 oldContextType = DRI_3D_CONTEXT;
   1828                 newContextStore = DRIGetContextStore(newContext);
   1829                 if ((newContext->valid3D) &&
   1830                     (newContext->hwContext != pDRIPriv->myContext)) {
   1831                     newContextType = DRI_3D_CONTEXT;
   1832                 }
   1833                 else {
   1834                     newContextType = DRI_2D_CONTEXT;
   1835                 }
   1836                 syncType = DRI_NO_SYNC;
   1837             }
   1838         }
   1839         else {
   1840             /* now setup for a complete 3D swap */
   1841             oldContextStore = newContextStore;
   1842             oldContext->valid3D = TRUE;
   1843             oldContextType = DRI_3D_CONTEXT;
   1844             newContextStore = DRIGetContextStore(newContext);
   1845             if ((newContext->valid3D) &&
   1846                 (newContext->hwContext != pDRIPriv->myContext)) {
   1847                 newContextType = DRI_3D_CONTEXT;
   1848             }
   1849             else {
   1850                 newContextType = DRI_2D_CONTEXT;
   1851             }
   1852             syncType = DRI_3D_SYNC;
   1853         }
   1854     }
   1855 
   1856     /* call DDX driver to perform the swap */
   1857     (*pDRIPriv->pDriverInfo->SwapContext) (pScreen,
   1858                                            syncType,
   1859                                            oldContextType,
   1860                                            oldContextStore,
   1861                                            newContextType, newContextStore);
   1862 }
   1863 
   1864 void *
   1865 DRIGetContextStore(DRIContextPrivPtr context)
   1866 {
   1867     return ((void *) context->pContextStore);
   1868 }
   1869 
   1870 void
   1871 DRIWindowExposures(WindowPtr pWin, RegionPtr prgn)
   1872 {
   1873     ScreenPtr pScreen = pWin->drawable.pScreen;
   1874     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1875     DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
   1876 
   1877     if (pDRIDrawablePriv) {
   1878         (*pDRIPriv->pDriverInfo->InitBuffers) (pWin, prgn,
   1879                                                pDRIDrawablePriv->drawableIndex);
   1880     }
   1881 
   1882     /* call lower wrapped functions */
   1883     if (pDRIPriv && pDRIPriv->wrap.WindowExposures) {
   1884 
   1885         /* unwrap */
   1886         pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
   1887 
   1888         /* call lower layers */
   1889         (*pScreen->WindowExposures) (pWin, prgn);
   1890 
   1891         /* rewrap */
   1892         pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
   1893         pScreen->WindowExposures = DRIWindowExposures;
   1894     }
   1895 }
   1896 
   1897 static int
   1898 DRITreeTraversal(WindowPtr pWin, void *data)
   1899 {
   1900     DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
   1901 
   1902     if (pDRIDrawablePriv) {
   1903         ScreenPtr pScreen = pWin->drawable.pScreen;
   1904         DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1905 
   1906         if (RegionNumRects(&(pWin->clipList)) > 0) {
   1907             RegionPtr reg = (RegionPtr) data;
   1908 
   1909             RegionUnion(reg, reg, &(pWin->clipList));
   1910             pDRIPriv->nrWalked++;
   1911         }
   1912 
   1913         if (pDRIPriv->nrWindows == pDRIPriv->nrWalked)
   1914             return WT_STOPWALKING;
   1915     }
   1916     return WT_WALKCHILDREN;
   1917 }
   1918 
   1919 Bool
   1920 DRIDestroyWindow(WindowPtr pWin)
   1921 {
   1922     ScreenPtr pScreen = pWin->drawable.pScreen;
   1923     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1924     Bool retval = TRUE;
   1925 
   1926     DRIDrawablePrivDestroy(pWin);
   1927 
   1928     /* call lower wrapped functions */
   1929     if (pDRIPriv->DestroyWindow) {
   1930         /* unwrap */
   1931         pScreen->DestroyWindow = pDRIPriv->DestroyWindow;
   1932 
   1933         /* call lower layers */
   1934         retval = (*pScreen->DestroyWindow) (pWin);
   1935 
   1936         /* rewrap */
   1937         pDRIPriv->DestroyWindow = pScreen->DestroyWindow;
   1938         pScreen->DestroyWindow = DRIDestroyWindow;
   1939     }
   1940 
   1941     return retval;
   1942 }
   1943 
   1944 void
   1945 DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
   1946 {
   1947     ScreenPtr pScreen = pWin->drawable.pScreen;
   1948     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   1949 
   1950     if (!pDRIPriv)
   1951         return;
   1952 
   1953     if (pDRIPriv->nrWindowsVisible > 0) {
   1954         RegionRec reg;
   1955 
   1956         RegionNull(&reg);
   1957         pDRIPriv->nrWalked = 0;
   1958         TraverseTree(pWin, DRITreeTraversal, (void *) (&reg));
   1959 
   1960         if (RegionNotEmpty(&reg)) {
   1961             RegionTranslate(&reg, ptOldOrg.x - pWin->drawable.x,
   1962                             ptOldOrg.y - pWin->drawable.y);
   1963             RegionIntersect(&reg, &reg, prgnSrc);
   1964 
   1965             /* The MoveBuffers interface is not ideal */
   1966             (*pDRIPriv->pDriverInfo->MoveBuffers) (pWin, ptOldOrg, &reg,
   1967                                                    pDRIPriv->pDriverInfo->
   1968                                                    ddxDrawableTableEntry);
   1969         }
   1970 
   1971         RegionUninit(&reg);
   1972     }
   1973 
   1974     /* call lower wrapped functions */
   1975     if (pDRIPriv->wrap.CopyWindow) {
   1976         /* unwrap */
   1977         pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
   1978 
   1979         /* call lower layers */
   1980         (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc);
   1981 
   1982         /* rewrap */
   1983         pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
   1984         pScreen->CopyWindow = DRICopyWindow;
   1985     }
   1986 }
   1987 
   1988 static void
   1989 DRIGetSecs(long *secs, long *usecs)
   1990 {
   1991     struct timeval tv;
   1992 
   1993     gettimeofday(&tv, NULL);
   1994 
   1995     *secs = tv.tv_sec;
   1996     *usecs = tv.tv_usec;
   1997 }
   1998 
   1999 static unsigned long
   2000 DRIComputeMilliSeconds(unsigned long s_secs, unsigned long s_usecs,
   2001                        unsigned long f_secs, unsigned long f_usecs)
   2002 {
   2003     if (f_usecs < s_usecs) {
   2004         --f_secs;
   2005         f_usecs += 1000000;
   2006     }
   2007     return (f_secs - s_secs) * 1000 + (f_usecs - s_usecs) / 1000;
   2008 }
   2009 
   2010 static void
   2011 DRISpinLockTimeout(drmLock * lock, int val, unsigned long timeout /* in mS */ )
   2012 {
   2013     int count = 10000;
   2014 
   2015 #if !defined(__alpha__) && !defined(__powerpc__)
   2016     char ret;
   2017 #else
   2018     int ret;
   2019 #endif
   2020     long s_secs, s_usecs;
   2021     long f_secs, f_usecs;
   2022     long msecs;
   2023     long prev = 0;
   2024 
   2025     DRIGetSecs(&s_secs, &s_usecs);
   2026 
   2027     do {
   2028         DRM_SPINLOCK_COUNT(lock, val, count, ret);
   2029         if (!ret)
   2030             return;             /* Got lock */
   2031         DRIGetSecs(&f_secs, &f_usecs);
   2032         msecs = DRIComputeMilliSeconds(s_secs, s_usecs, f_secs, f_usecs);
   2033         if (msecs - prev < 250)
   2034             count *= 2;         /* Not more than 0.5S */
   2035     } while (msecs < timeout);
   2036 
   2037     /* Didn't get lock, so take it.  The worst
   2038        that can happen is that there is some
   2039        garbage written to the wrong part of the
   2040        framebuffer that a refresh will repair.
   2041        That's undesirable, but better than
   2042        locking the server.  This should be a
   2043        very rare event. */
   2044     DRM_SPINLOCK_TAKE(lock, val);
   2045 }
   2046 
   2047 static void
   2048 DRILockTree(ScreenPtr pScreen)
   2049 {
   2050     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2051 
   2052     if (!pDRIPriv)
   2053         return;
   2054 
   2055     /* Restore the last known 3D context if the X context is hidden */
   2056     if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
   2057         (*pDRIPriv->pDriverInfo->SwapContext) (pScreen,
   2058                                                DRI_2D_SYNC,
   2059                                                DRI_NO_CONTEXT,
   2060                                                NULL,
   2061                                                DRI_2D_CONTEXT,
   2062                                                pDRIPriv->partial3DContextStore);
   2063     }
   2064 
   2065     /* Call kernel to release lock */
   2066     DRIUnlock(pScreen);
   2067 
   2068     /* Grab drawable spin lock: a time out between 10 and 30 seconds is
   2069        appropriate, since this should never time out except in the case of
   2070        client death while the lock is being held.  The timeout must be
   2071        greater than any reasonable rendering time. */
   2072     DRISpinLockTimeout(&pDRIPriv->pSAREA->drawable_lock, 1, 10000);     /*10 secs */
   2073 
   2074     /* Call kernel flush outstanding buffers and relock */
   2075     DRILock(pScreen, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH_ALL);
   2076 
   2077     /* Switch back to our 2D context if the X context is hidden */
   2078     if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
   2079         /* hide X context by swapping 2D component here */
   2080         (*pDRIPriv->pDriverInfo->SwapContext) (pScreen,
   2081                                                DRI_3D_SYNC,
   2082                                                DRI_2D_CONTEXT,
   2083                                                pDRIPriv->partial3DContextStore,
   2084                                                DRI_2D_CONTEXT,
   2085                                                pDRIPriv->hiddenContextStore);
   2086     }
   2087 }
   2088 
   2089 void
   2090 DRIClipNotify(WindowPtr pWin, int dx, int dy)
   2091 {
   2092     ScreenPtr pScreen = pWin->drawable.pScreen;
   2093     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2094     DRIDrawablePrivPtr pDRIDrawablePriv;
   2095 
   2096     if (!pDRIPriv)
   2097         return;
   2098 
   2099     if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
   2100         int nrects = RegionNumRects(&pWin->clipList);
   2101 
   2102         if (!pDRIPriv->windowsTouched) {
   2103             DRILockTree(pScreen);
   2104             pDRIPriv->windowsTouched = TRUE;
   2105         }
   2106 
   2107         if (nrects && !pDRIDrawablePriv->nrects)
   2108             DRIIncreaseNumberVisible(pScreen);
   2109         else if (!nrects && pDRIDrawablePriv->nrects)
   2110             DRIDecreaseNumberVisible(pScreen);
   2111         else
   2112             DRIDriverClipNotify(pScreen);
   2113 
   2114         pDRIDrawablePriv->nrects = nrects;
   2115 
   2116         pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
   2117             = DRIDrawableValidationStamp++;
   2118 
   2119         drmUpdateDrawableInfo(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable,
   2120                               DRM_DRAWABLE_CLIPRECTS,
   2121                               nrects, RegionRects(&pWin->clipList));
   2122     }
   2123 
   2124     /* call lower wrapped functions */
   2125     if (pDRIPriv->wrap.ClipNotify) {
   2126 
   2127         /* unwrap */
   2128         pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
   2129 
   2130         /* call lower layers */
   2131         (*pScreen->ClipNotify) (pWin, dx, dy);
   2132 
   2133         /* rewrap */
   2134         pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
   2135         pScreen->ClipNotify = DRIClipNotify;
   2136     }
   2137 }
   2138 
   2139 CARD32
   2140 DRIGetDrawableIndex(WindowPtr pWin)
   2141 {
   2142     ScreenPtr pScreen = pWin->drawable.pScreen;
   2143     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2144     DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
   2145     CARD32 index;
   2146 
   2147     if (pDRIDrawablePriv) {
   2148         index = pDRIDrawablePriv->drawableIndex;
   2149     }
   2150     else {
   2151         index = pDRIPriv->pDriverInfo->ddxDrawableTableEntry;
   2152     }
   2153 
   2154     return index;
   2155 }
   2156 
   2157 unsigned int
   2158 DRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index)
   2159 {
   2160     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2161 
   2162     return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp;
   2163 }
   2164 
   2165 void
   2166 DRIPrintDrawableLock(ScreenPtr pScreen, char *msg)
   2167 {
   2168     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2169 
   2170     ErrorF("%s: %d\n", msg, pDRIPriv->pSAREA->drawable_lock.lock);
   2171 }
   2172 
   2173 void
   2174 DRILock(ScreenPtr pScreen, int flags)
   2175 {
   2176     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2177 
   2178     if (!pDRIPriv || !pDRIPriv->pLockRefCount)
   2179         return;
   2180 
   2181     if (!*pDRIPriv->pLockRefCount) {
   2182         DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext,
   2183                  flags);
   2184         *pDRIPriv->pLockingContext = pDRIPriv->myContext;
   2185     }
   2186     else if (*pDRIPriv->pLockingContext != pDRIPriv->myContext) {
   2187         DRIDrvMsg(pScreen->myNum, X_ERROR,
   2188                   "[DRI] Locking deadlock.\n"
   2189                   "\tAlready locked with context %p,\n"
   2190                   "\ttrying to lock with context %p.\n",
   2191                   pDRIPriv->pLockingContext, (void *) (uintptr_t) pDRIPriv->myContext);
   2192     }
   2193     (*pDRIPriv->pLockRefCount)++;
   2194 }
   2195 
   2196 void
   2197 DRIUnlock(ScreenPtr pScreen)
   2198 {
   2199     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2200 
   2201     if (!pDRIPriv || !pDRIPriv->pLockRefCount)
   2202         return;
   2203 
   2204     if (*pDRIPriv->pLockRefCount > 0) {
   2205         if (pDRIPriv->myContext != *pDRIPriv->pLockingContext) {
   2206             DRIDrvMsg(pScreen->myNum, X_ERROR,
   2207                       "[DRI] Unlocking inconsistency:\n"
   2208                       "\tContext %p trying to unlock lock held by context %p\n",
   2209                       pDRIPriv->pLockingContext, (void *) (uintptr_t) pDRIPriv->myContext);
   2210         }
   2211         (*pDRIPriv->pLockRefCount)--;
   2212     }
   2213     else {
   2214         DRIDrvMsg(pScreen->myNum, X_ERROR,
   2215                   "DRIUnlock called when not locked.\n");
   2216         return;
   2217     }
   2218     if (!*pDRIPriv->pLockRefCount)
   2219         DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext);
   2220 }
   2221 
   2222 void *
   2223 DRIGetSAREAPrivate(ScreenPtr pScreen)
   2224 {
   2225     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2226 
   2227     if (!pDRIPriv)
   2228         return 0;
   2229 
   2230     return (void *) (((char *) pDRIPriv->pSAREA) + sizeof(XF86DRISAREARec));
   2231 }
   2232 
   2233 drm_context_t
   2234 DRIGetContext(ScreenPtr pScreen)
   2235 {
   2236     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2237 
   2238     if (!pDRIPriv)
   2239         return 0;
   2240 
   2241     return pDRIPriv->myContext;
   2242 }
   2243 
   2244 void
   2245 DRIGetTexOffsetFuncs(ScreenPtr pScreen,
   2246                      DRITexOffsetStartProcPtr * texOffsetStartFunc,
   2247                      DRITexOffsetFinishProcPtr * texOffsetFinishFunc)
   2248 {
   2249     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2250 
   2251     if (!pDRIPriv)
   2252         return;
   2253 
   2254     *texOffsetStartFunc = pDRIPriv->pDriverInfo->texOffsetStart;
   2255     *texOffsetFinishFunc = pDRIPriv->pDriverInfo->texOffsetFinish;
   2256 }
   2257 
   2258 /* This lets get at the unwrapped functions so that they can correctly
   2259  * call the lowerlevel functions, and choose whether they will be
   2260  * called at every level of recursion (eg in validatetree).
   2261  */
   2262 DRIWrappedFuncsRec *
   2263 DRIGetWrappedFuncs(ScreenPtr pScreen)
   2264 {
   2265     return &(DRI_SCREEN_PRIV(pScreen)->wrap);
   2266 }
   2267 
   2268 /* note that this returns the library version, not the protocol version */
   2269 void
   2270 DRIQueryVersion(int *majorVersion, int *minorVersion, int *patchVersion)
   2271 {
   2272     *majorVersion = DRIINFO_MAJOR_VERSION;
   2273     *minorVersion = DRIINFO_MINOR_VERSION;
   2274     *patchVersion = DRIINFO_PATCH_VERSION;
   2275 }
   2276 
   2277 static void
   2278 _DRIAdjustFrame(ScrnInfoPtr pScrn, DRIScreenPrivPtr pDRIPriv, int x, int y)
   2279 {
   2280     pDRIPriv->pSAREA->frame.x = x;
   2281     pDRIPriv->pSAREA->frame.y = y;
   2282     pDRIPriv->pSAREA->frame.width = pScrn->frameX1 - x + 1;
   2283     pDRIPriv->pSAREA->frame.height = pScrn->frameY1 - y + 1;
   2284 }
   2285 
   2286 void
   2287 DRIAdjustFrame(ScrnInfoPtr pScrn, int x, int y)
   2288 {
   2289     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
   2290     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
   2291     int px, py;
   2292 
   2293     if (!pDRIPriv || !pDRIPriv->pSAREA) {
   2294         DRIDrvMsg(pScrn->scrnIndex, X_ERROR, "[DRI] No SAREA (%p %p)\n",
   2295                   pDRIPriv, pDRIPriv ? pDRIPriv->pSAREA : NULL);
   2296         return;
   2297     }
   2298 
   2299     if (pDRIPriv->fullscreen) {
   2300         /* Fix up frame */
   2301         pScrn->frameX0 = pDRIPriv->pSAREA->frame.x;
   2302         pScrn->frameY0 = pDRIPriv->pSAREA->frame.y;
   2303         pScrn->frameX1 = pScrn->frameX0 + pDRIPriv->pSAREA->frame.width - 1;
   2304         pScrn->frameY1 = pScrn->frameY0 + pDRIPriv->pSAREA->frame.height - 1;
   2305 
   2306         /* Fix up cursor */
   2307         miPointerGetPosition(inputInfo.pointer, &px, &py);
   2308 
   2309         if (px < pScrn->frameX0)
   2310             px = pScrn->frameX0;
   2311         if (px > pScrn->frameX1)
   2312             px = pScrn->frameX1;
   2313         if (py < pScrn->frameY0)
   2314             py = pScrn->frameY0;
   2315         if (py > pScrn->frameY1)
   2316             py = pScrn->frameY1;
   2317         pScreen->SetCursorPosition(inputInfo.pointer, pScreen, px, py, TRUE);
   2318 
   2319         return;
   2320     }
   2321 
   2322     if (pDRIPriv->wrap.AdjustFrame) {
   2323         /* unwrap */
   2324         pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
   2325         /* call lower layers */
   2326         (*pScrn->AdjustFrame) (pScrn, x, y);
   2327         /* rewrap */
   2328         pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
   2329         pScrn->AdjustFrame = DRIAdjustFrame;
   2330     }
   2331 
   2332     _DRIAdjustFrame(pScrn, pDRIPriv, x, y);
   2333 }
   2334 
   2335 /*
   2336  * DRIMoveBuffersHelper swaps the regions rects in place leaving you
   2337  * a region with the rects in the order that you need to blit them,
   2338  * but it is possibly (likely) an invalid region afterwards.  If you
   2339  * need to use the region again for anything you have to call
   2340  * REGION_VALIDATE on it, or better yet, save a copy first.
   2341  */
   2342 
   2343 void
   2344 DRIMoveBuffersHelper(ScreenPtr pScreen,
   2345                      int dx, int dy, int *xdir, int *ydir, RegionPtr reg)
   2346 {
   2347     BoxPtr extents, pbox, firstBox, lastBox;
   2348     BoxRec tmpBox;
   2349     int y, nbox;
   2350 
   2351     extents = RegionExtents(reg);
   2352     nbox = RegionNumRects(reg);
   2353     pbox = RegionRects(reg);
   2354 
   2355     if ((dy > 0) && (dy < (extents->y2 - extents->y1))) {
   2356         *ydir = -1;
   2357         if (nbox > 1) {
   2358             firstBox = pbox;
   2359             lastBox = pbox + nbox - 1;
   2360             while ((unsigned long) firstBox < (unsigned long) lastBox) {
   2361                 tmpBox = *firstBox;
   2362                 *firstBox = *lastBox;
   2363                 *lastBox = tmpBox;
   2364                 firstBox++;
   2365                 lastBox--;
   2366             }
   2367         }
   2368     }
   2369     else
   2370         *ydir = 1;
   2371 
   2372     if ((dx > 0) && (dx < (extents->x2 - extents->x1))) {
   2373         *xdir = -1;
   2374         if (nbox > 1) {
   2375             firstBox = lastBox = pbox;
   2376             y = pbox->y1;
   2377             while (--nbox) {
   2378                 pbox++;
   2379                 if (pbox->y1 == y)
   2380                     lastBox++;
   2381                 else {
   2382                     while ((unsigned long) firstBox < (unsigned long) lastBox) {
   2383                         tmpBox = *firstBox;
   2384                         *firstBox = *lastBox;
   2385                         *lastBox = tmpBox;
   2386                         firstBox++;
   2387                         lastBox--;
   2388                     }
   2389 
   2390                     firstBox = lastBox = pbox;
   2391                     y = pbox->y1;
   2392                 }
   2393             }
   2394             while ((unsigned long) firstBox < (unsigned long) lastBox) {
   2395                 tmpBox = *firstBox;
   2396                 *firstBox = *lastBox;
   2397                 *lastBox = tmpBox;
   2398                 firstBox++;
   2399                 lastBox--;
   2400             }
   2401         }
   2402     }
   2403     else
   2404         *xdir = 1;
   2405 
   2406 }