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