1/**************************************************************************
2
3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4Copyright 2000 VA Linux Systems, Inc.
5All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sub license, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice (including the
16next paragraph) shall be included in all copies or substantial portions
17of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25SOFTWARE 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
74static int DRIEntPrivIndex = -1;
75static DevPrivateKeyRec DRIScreenPrivKeyRec;
76
77#define DRIScreenPrivKey (&DRIScreenPrivKeyRec)
78static DevPrivateKeyRec DRIWindowPrivKeyRec;
79
80#define DRIWindowPrivKey (&DRIWindowPrivKeyRec)
81static unsigned long DRIGeneration = 0;
82static unsigned int DRIDrawableValidationStamp = 0;
83
84static RESTYPE DRIDrawablePrivResType;
85static RESTYPE DRIContextPrivResType;
86static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv);
87
88drmServerInfo 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
104static void
105DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...)
106    _X_ATTRIBUTE_PRINTF(3,4);
107
108static void
109DRIDrvMsg(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
118static void
119DRIOpenDRMCleanup(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
134int
135DRIMasterFD(ScrnInfoPtr pScrn)
136{
137    return DRI_ENT_PRIV(pScrn)->drmFD;
138}
139
140void *
141DRIMasterSareaPointer(ScrnInfoPtr pScrn)
142{
143    return DRI_ENT_PRIV(pScrn)->pLSAREA;
144}
145
146drm_handle_t
147DRIMasterSareaHandle(ScrnInfoPtr pScrn)
148{
149    return DRI_ENT_PRIV(pScrn)->hLSAREA;
150}
151
152Bool
153DRIOpenDRMMaster(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
278static void
279 DRIClipNotifyAllDrawables(ScreenPtr pScreen);
280
281static void
282dri_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
293static void
294drmSIGIOHandler(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
334static int
335drmInstallSIGIOHandler(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
345static int
346drmRemoveSIGIOHandler(int fd)
347{
348    drmHashEntry *entry = drmGetEntry(fd);
349
350    entry->f = NULL;
351
352    return xf86RemoveSIGIOHandler(fd);
353}
354
355Bool
356DRIScreenInit(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
633Bool
634DRIFinishScreenInit(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
672void
673DRICloseScreen(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
789static int
790dri_drm_debug_print(const char *format, va_list ap)
791    _X_ATTRIBUTE_PRINTF(1,0);
792
793static int
794dri_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
800static void
801dri_drm_get_perms(gid_t * group, mode_t * mode)
802{
803    *group = xf86ConfigDRI.group;
804    *mode = xf86ConfigDRI.mode;
805}
806
807drmServerInfo DRIDRMServerInfo = {
808    dri_drm_debug_print,
809    xf86LoadKernelModule,
810    dri_drm_get_perms,
811};
812
813Bool
814DRIExtensionInit(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
833void
834DRIReset(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
845Bool
846DRIQueryDirectRenderingCapable(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
858Bool
859DRIOpenConnection(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
869Bool
870DRIAuthConnection(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
879Bool
880DRICloseConnection(ScreenPtr pScreen)
881{
882    return TRUE;
883}
884
885Bool
886DRIGetClientDriverName(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
913DRIContextPrivPtr
914DRICreateContextPriv(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
926DRIContextPrivPtr
927DRICreateContextPrivFromHandle(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
968Bool
969DRIDestroyContextPriv(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
996static Bool
997DRICreateDummyContext(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
1024static void
1025DRIDestroyDummyContext(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
1045Bool
1046DRICreateContext(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
1083Bool
1084DRIDestroyContext(ScreenPtr pScreen, XID context)
1085{
1086    FreeResourceByType(context, DRIContextPrivResType, FALSE);
1087
1088    return TRUE;
1089}
1090
1091/* DRIContextPrivDelete is called by the resource manager. */
1092Bool
1093DRIContextPrivDelete(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 */
1116static void
1117DRIClipNotifyAllDrawables(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
1127static void
1128DRITransitionToSharedBuffers(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
1139static void
1140DRITransitionToPrivateBuffers(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
1151static void
1152DRITransitionTo3d(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
1163static void
1164DRITransitionTo2d(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
1175static int
1176DRIDCNTreeTraversal(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
1203static void
1204DRIDriverClipNotify(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
1224static void
1225DRIIncreaseNumberVisible(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
1243static void
1244DRIDecreaseNumberVisible(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
1262Bool
1263DRICreateDrawable(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
1330static void
1331DRIDrawablePrivDestroy(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
1363static Bool
1364DRIDestroyDrawableCB(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
1376Bool
1377DRIDestroyDrawable(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
1392Bool
1393DRIDrawablePrivDelete(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
1420Bool
1421DRIGetDrawableInfo(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
1597Bool
1598DRIGetDeviceInfo(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
1616DRIInfoPtr
1617DRICreateInfoRec(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
1642void
1643DRIDestroyInfoRec(DRIInfoPtr DRIInfo)
1644{
1645    free(DRIInfo->busIdString);
1646    free((char *) DRIInfo);
1647}
1648
1649void
1650DRIWakeupHandler(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
1663void
1664DRIBlockHandler(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
1677void
1678DRIDoWakeupHandler(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
1694void
1695DRIDoBlockHandler(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
1716void
1717DRISwapContext(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
1864void *
1865DRIGetContextStore(DRIContextPrivPtr context)
1866{
1867    return ((void *) context->pContextStore);
1868}
1869
1870void
1871DRIWindowExposures(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
1897static int
1898DRITreeTraversal(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
1919Bool
1920DRIDestroyWindow(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
1944void
1945DRICopyWindow(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
1988static void
1989DRIGetSecs(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
1999static unsigned long
2000DRIComputeMilliSeconds(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
2010static void
2011DRISpinLockTimeout(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
2047static void
2048DRILockTree(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
2089void
2090DRIClipNotify(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
2139CARD32
2140DRIGetDrawableIndex(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
2157unsigned int
2158DRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index)
2159{
2160    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2161
2162    return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp;
2163}
2164
2165void
2166DRIPrintDrawableLock(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
2173void
2174DRILock(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
2196void
2197DRIUnlock(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
2222void *
2223DRIGetSAREAPrivate(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
2233drm_context_t
2234DRIGetContext(ScreenPtr pScreen)
2235{
2236    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2237
2238    if (!pDRIPriv)
2239        return 0;
2240
2241    return pDRIPriv->myContext;
2242}
2243
2244void
2245DRIGetTexOffsetFuncs(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 */
2262DRIWrappedFuncsRec *
2263DRIGetWrappedFuncs(ScreenPtr pScreen)
2264{
2265    return &(DRI_SCREEN_PRIV(pScreen)->wrap);
2266}
2267
2268/* note that this returns the library version, not the protocol version */
2269void
2270DRIQueryVersion(int *majorVersion, int *minorVersion, int *patchVersion)
2271{
2272    *majorVersion = DRIINFO_MAJOR_VERSION;
2273    *minorVersion = DRIINFO_MINOR_VERSION;
2274    *patchVersion = DRIINFO_PATCH_VERSION;
2275}
2276
2277static 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
2286void
2287DRIAdjustFrame(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
2343void
2344DRIMoveBuffersHelper(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}
2407