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