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