1706f2543Smrg/**************************************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4706f2543SmrgCopyright 2000 VA Linux Systems, Inc.
5706f2543SmrgAll Rights Reserved.
6706f2543Smrg
7706f2543SmrgPermission is hereby granted, free of charge, to any person obtaining a
8706f2543Smrgcopy of this software and associated documentation files (the
9706f2543Smrg"Software"), to deal in the Software without restriction, including
10706f2543Smrgwithout limitation the rights to use, copy, modify, merge, publish,
11706f2543Smrgdistribute, sub license, and/or sell copies of the Software, and to
12706f2543Smrgpermit persons to whom the Software is furnished to do so, subject to
13706f2543Smrgthe following conditions:
14706f2543Smrg
15706f2543SmrgThe above copyright notice and this permission notice (including the
16706f2543Smrgnext paragraph) shall be included in all copies or substantial portions
17706f2543Smrgof the Software.
18706f2543Smrg
19706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20706f2543SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21706f2543SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22706f2543SmrgIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23706f2543SmrgANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24706f2543SmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25706f2543SmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26706f2543Smrg
27706f2543Smrg**************************************************************************/
28706f2543Smrg
29706f2543Smrg/*
30706f2543Smrg * Authors:
31706f2543Smrg *   Jens Owen <jens@tungstengraphics.com>
32706f2543Smrg *   Rickard E. (Rik) Faith <faith@valinux.com>
33706f2543Smrg *
34706f2543Smrg */
35706f2543Smrg
36706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
37706f2543Smrg#include <xorg-config.h>
38706f2543Smrg#endif
39706f2543Smrg
40706f2543Smrg#include "xf86.h"
41706f2543Smrg#include <sys/time.h>
42706f2543Smrg#include <unistd.h>
43706f2543Smrg#include <string.h>
44706f2543Smrg#include <stdio.h>
45706f2543Smrg#include <sys/ioctl.h>
46706f2543Smrg#include <errno.h>
47706f2543Smrg
48706f2543Smrg#include <X11/X.h>
49706f2543Smrg#include <X11/Xproto.h>
50706f2543Smrg#include "xf86drm.h"
51706f2543Smrg#include "misc.h"
52706f2543Smrg#include "dixstruct.h"
53706f2543Smrg#include "extnsionst.h"
54706f2543Smrg#include "colormapst.h"
55706f2543Smrg#include "cursorstr.h"
56706f2543Smrg#include "scrnintstr.h"
57706f2543Smrg#include "windowstr.h"
58706f2543Smrg#include "servermd.h"
59706f2543Smrg#define _XF86DRI_SERVER_
60706f2543Smrg#include <X11/dri/xf86driproto.h>
61706f2543Smrg#include "swaprep.h"
62706f2543Smrg#include "xf86str.h"
63706f2543Smrg#include "dri.h"
64706f2543Smrg#include "sarea.h"
65706f2543Smrg#include "dristruct.h"
66706f2543Smrg#include "xf86.h"
67706f2543Smrg#include "xf86drm.h"
68706f2543Smrg#include "mi.h"
69706f2543Smrg#include "mipointer.h"
70706f2543Smrg#include "xf86_OSproc.h"
71706f2543Smrg#include "inputstr.h"
72706f2543Smrg#include "xf86VGAarbiter.h"
73706f2543Smrg
74706f2543Smrgstatic int DRIEntPrivIndex = -1;
75706f2543Smrgstatic DevPrivateKeyRec DRIScreenPrivKeyRec;
76706f2543Smrg#define DRIScreenPrivKey (&DRIScreenPrivKeyRec)
77706f2543Smrgstatic DevPrivateKeyRec DRIWindowPrivKeyRec;
78706f2543Smrg#define DRIWindowPrivKey (&DRIWindowPrivKeyRec)
79706f2543Smrgstatic unsigned long DRIGeneration = 0;
80706f2543Smrgstatic unsigned int DRIDrawableValidationStamp = 0;
81706f2543Smrg
82706f2543Smrgstatic RESTYPE DRIDrawablePrivResType;
83706f2543Smrgstatic RESTYPE DRIContextPrivResType;
84706f2543Smrgstatic void    DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv);
85706f2543Smrg
86706f2543SmrgdrmServerInfo DRIDRMServerInfo;
87706f2543Smrg
88706f2543Smrg				/* Wrapper just like xf86DrvMsg, but
89706f2543Smrg				   without the verbosity level checking.
90706f2543Smrg				   This will make it easy to turn off some
91706f2543Smrg				   messages later, based on verbosity
92706f2543Smrg				   level. */
93706f2543Smrg
94706f2543Smrg/*
95706f2543Smrg * Since we're already referencing things from the XFree86 common layer in
96706f2543Smrg * this file, we'd might as well just call xf86VDrvMsgVerb, and have
97706f2543Smrg * consistent message formatting.  The verbosity of these messages can be
98706f2543Smrg * easily changed here.
99706f2543Smrg */
100706f2543Smrg#define DRI_MSG_VERBOSITY 1
101706f2543Smrgstatic void
102706f2543SmrgDRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...)
103706f2543Smrg{
104706f2543Smrg    va_list     ap;
105706f2543Smrg
106706f2543Smrg    va_start(ap, format);
107706f2543Smrg    xf86VDrvMsgVerb(scrnIndex, type, DRI_MSG_VERBOSITY, format, ap);
108706f2543Smrg    va_end(ap);
109706f2543Smrg}
110706f2543Smrg
111706f2543Smrg
112706f2543Smrgstatic void
113706f2543SmrgDRIOpenDRMCleanup(DRIEntPrivPtr pDRIEntPriv)
114706f2543Smrg{
115706f2543Smrg    if (pDRIEntPriv->pLSAREA != NULL) {
116706f2543Smrg	drmUnmap(pDRIEntPriv->pLSAREA, pDRIEntPriv->sAreaSize);
117706f2543Smrg	pDRIEntPriv->pLSAREA = NULL;
118706f2543Smrg    }
119706f2543Smrg    if (pDRIEntPriv->hLSAREA != 0) {
120706f2543Smrg	drmRmMap(pDRIEntPriv->drmFD, pDRIEntPriv->hLSAREA);
121706f2543Smrg    }
122706f2543Smrg    if (pDRIEntPriv->drmFD >= 0) {
123706f2543Smrg	drmClose(pDRIEntPriv->drmFD);
124706f2543Smrg	pDRIEntPriv->drmFD = 0;
125706f2543Smrg    }
126706f2543Smrg}
127706f2543Smrg
128706f2543Smrgint
129706f2543SmrgDRIMasterFD(ScrnInfoPtr pScrn)
130706f2543Smrg{
131706f2543Smrg    return DRI_ENT_PRIV(pScrn)->drmFD;
132706f2543Smrg}
133706f2543Smrg
134706f2543Smrgvoid *
135706f2543SmrgDRIMasterSareaPointer(ScrnInfoPtr pScrn)
136706f2543Smrg{
137706f2543Smrg    return DRI_ENT_PRIV(pScrn)->pLSAREA;
138706f2543Smrg}
139706f2543Smrg
140706f2543Smrgdrm_handle_t
141706f2543SmrgDRIMasterSareaHandle(ScrnInfoPtr pScrn)
142706f2543Smrg{
143706f2543Smrg    return DRI_ENT_PRIV(pScrn)->hLSAREA;
144706f2543Smrg}
145706f2543Smrg
146706f2543Smrg
147706f2543SmrgBool
148706f2543SmrgDRIOpenDRMMaster(ScrnInfoPtr pScrn,
149706f2543Smrg		 unsigned long sAreaSize,
150706f2543Smrg		 const char *busID,
151706f2543Smrg		 const char *drmDriverName)
152706f2543Smrg{
153706f2543Smrg    drmSetVersion saveSv, sv;
154706f2543Smrg    Bool drmWasAvailable;
155706f2543Smrg    DRIEntPrivPtr pDRIEntPriv;
156706f2543Smrg    DRIEntPrivRec tmp;
157706f2543Smrg    drmVersionPtr drmlibv;
158706f2543Smrg    int drmlibmajor, drmlibminor;
159706f2543Smrg    const char *openBusID;
160706f2543Smrg    int count;
161706f2543Smrg    int err;
162706f2543Smrg
163706f2543Smrg    if (DRIEntPrivIndex == -1)
164706f2543Smrg	DRIEntPrivIndex = xf86AllocateEntityPrivateIndex();
165706f2543Smrg
166706f2543Smrg    pDRIEntPriv = DRI_ENT_PRIV(pScrn);
167706f2543Smrg
168706f2543Smrg    if (pDRIEntPriv && pDRIEntPriv->drmFD != -1)
169706f2543Smrg	return TRUE;
170706f2543Smrg
171706f2543Smrg    drmWasAvailable = drmAvailable();
172706f2543Smrg
173706f2543Smrg    memset(&tmp, 0, sizeof(tmp));
174706f2543Smrg
175706f2543Smrg    /* Check the DRM lib version.
176706f2543Smrg     * drmGetLibVersion was not supported in version 1.0, so check for
177706f2543Smrg     * symbol first to avoid possible crash or hang.
178706f2543Smrg     */
179706f2543Smrg
180706f2543Smrg    drmlibmajor = 1;
181706f2543Smrg    drmlibminor = 0;
182706f2543Smrg    if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
183706f2543Smrg	drmlibv = drmGetLibVersion(-1);
184706f2543Smrg	if (drmlibv != NULL) {
185706f2543Smrg	    drmlibmajor = drmlibv->version_major;
186706f2543Smrg	    drmlibminor = drmlibv->version_minor;
187706f2543Smrg	    drmFreeVersion(drmlibv);
188706f2543Smrg	}
189706f2543Smrg    }
190706f2543Smrg
191706f2543Smrg    /* Check if the libdrm can handle falling back to loading based on name
192706f2543Smrg     * if a busid string is passed.
193706f2543Smrg     */
194706f2543Smrg    openBusID = (drmlibmajor == 1 && drmlibminor >= 2) ? busID : NULL;
195706f2543Smrg
196706f2543Smrg    tmp.drmFD = -1;
197706f2543Smrg    sv.drm_di_major = 1;
198706f2543Smrg    sv.drm_di_minor = 1;
199706f2543Smrg    sv.drm_dd_major = -1;
200706f2543Smrg
201706f2543Smrg    saveSv = sv;
202706f2543Smrg    count = 10;
203706f2543Smrg    while (count--) {
204706f2543Smrg	tmp.drmFD = drmOpen(drmDriverName, openBusID);
205706f2543Smrg
206706f2543Smrg	if (tmp.drmFD < 0) {
207706f2543Smrg	    DRIDrvMsg(-1, X_ERROR, "[drm] drmOpen failed.\n");
208706f2543Smrg	    goto out_err;
209706f2543Smrg	}
210706f2543Smrg
211706f2543Smrg	err = drmSetInterfaceVersion(tmp.drmFD, &sv);
212706f2543Smrg
213706f2543Smrg	if (err != -EPERM)
214706f2543Smrg	    break;
215706f2543Smrg
216706f2543Smrg	sv = saveSv;
217706f2543Smrg	drmClose(tmp.drmFD);
218706f2543Smrg	tmp.drmFD = -1;
219706f2543Smrg	usleep(100000);
220706f2543Smrg    }
221706f2543Smrg
222706f2543Smrg    if (tmp.drmFD <= 0) {
223706f2543Smrg	DRIDrvMsg(-1, X_ERROR, "[drm] DRM was busy with another master.\n");
224706f2543Smrg	goto out_err;
225706f2543Smrg    }
226706f2543Smrg
227706f2543Smrg    if (!drmWasAvailable) {
228706f2543Smrg	DRIDrvMsg(-1, X_INFO,
229706f2543Smrg		  "[drm] loaded kernel module for \"%s\" driver.\n",
230706f2543Smrg		  drmDriverName);
231706f2543Smrg    }
232706f2543Smrg
233706f2543Smrg    if (err != 0) {
234706f2543Smrg	sv.drm_di_major = 1;
235706f2543Smrg	sv.drm_di_minor = 0;
236706f2543Smrg    }
237706f2543Smrg
238706f2543Smrg    DRIDrvMsg(-1, X_INFO, "[drm] DRM interface version %d.%d\n",
239706f2543Smrg	      sv.drm_di_major, sv.drm_di_minor);
240706f2543Smrg
241706f2543Smrg    if (sv.drm_di_major == 1 && sv.drm_di_minor >= 1)
242706f2543Smrg	err = 0;
243706f2543Smrg    else
244706f2543Smrg	err = drmSetBusid(tmp.drmFD, busID);
245706f2543Smrg
246706f2543Smrg    if (err) {
247706f2543Smrg	DRIDrvMsg(-1, X_ERROR, "[drm] Could not set DRM device bus ID.\n");
248706f2543Smrg	goto out_err;
249706f2543Smrg    }
250706f2543Smrg
251706f2543Smrg    /*
252706f2543Smrg     * Create a lock-containing sarea.
253706f2543Smrg     */
254706f2543Smrg
255706f2543Smrg    if (drmAddMap( tmp.drmFD, 0, sAreaSize, DRM_SHM,
256706f2543Smrg		   DRM_CONTAINS_LOCK, &tmp.hLSAREA) < 0) {
257706f2543Smrg        DRIDrvMsg(-1, X_INFO, "[drm] Could not create SAREA for DRM lock.\n");
258706f2543Smrg	tmp.hLSAREA = 0;
259706f2543Smrg	goto out_err;
260706f2543Smrg    }
261706f2543Smrg
262706f2543Smrg    if (drmMap( tmp.drmFD, tmp.hLSAREA, sAreaSize,
263706f2543Smrg		(drmAddressPtr)(&tmp.pLSAREA)) < 0) {
264706f2543Smrg        DRIDrvMsg(-1, X_INFO, "[drm] Mapping SAREA for DRM lock failed.\n");
265706f2543Smrg	tmp.pLSAREA = NULL;
266706f2543Smrg	goto out_err;
267706f2543Smrg    }
268706f2543Smrg
269706f2543Smrg    memset(tmp.pLSAREA, 0, sAreaSize);
270706f2543Smrg
271706f2543Smrg    /*
272706f2543Smrg     * Reserved contexts are handled by the first opened screen.
273706f2543Smrg     */
274706f2543Smrg
275706f2543Smrg    tmp.resOwner = NULL;
276706f2543Smrg
277706f2543Smrg    if (!pDRIEntPriv)
278706f2543Smrg	pDRIEntPriv = xnfcalloc(sizeof(*pDRIEntPriv), 1);
279706f2543Smrg
280706f2543Smrg    if (!pDRIEntPriv) {
281706f2543Smrg        DRIDrvMsg(-1, X_INFO, "[drm] Failed to allocate memory for "
282706f2543Smrg		  "DRM device.\n");
283706f2543Smrg	goto out_err;
284706f2543Smrg    }
285706f2543Smrg    *pDRIEntPriv = tmp;
286706f2543Smrg    xf86GetEntityPrivate((pScrn)->entityList[0],DRIEntPrivIndex)->ptr =
287706f2543Smrg	pDRIEntPriv;
288706f2543Smrg
289706f2543Smrg    DRIDrvMsg(-1, X_INFO, "[drm] DRM open master succeeded.\n");
290706f2543Smrg    return TRUE;
291706f2543Smrg
292706f2543Smrg  out_err:
293706f2543Smrg
294706f2543Smrg    DRIOpenDRMCleanup(&tmp);
295706f2543Smrg    return FALSE;
296706f2543Smrg}
297706f2543Smrg
298706f2543Smrgstatic void
299706f2543SmrgDRIClipNotifyAllDrawables(ScreenPtr pScreen);
300706f2543Smrg
301706f2543Smrgstatic void
302706f2543Smrgdri_crtc_notify(ScreenPtr pScreen)
303706f2543Smrg{
304706f2543Smrg    DRIScreenPrivPtr  pDRIPriv = DRI_SCREEN_PRIV(pScreen);
305706f2543Smrg    DRIClipNotifyAllDrawables(pScreen);
306706f2543Smrg    xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify);
307706f2543Smrg    xf86_crtc_notify(pScreen);
308706f2543Smrg    pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, dri_crtc_notify);
309706f2543Smrg}
310706f2543Smrg
311706f2543SmrgBool
312706f2543SmrgDRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD)
313706f2543Smrg{
314706f2543Smrg    DRIScreenPrivPtr    pDRIPriv;
315706f2543Smrg    drm_context_t *       reserved;
316706f2543Smrg    int                 reserved_count;
317706f2543Smrg    int                 i;
318706f2543Smrg    DRIEntPrivPtr       pDRIEntPriv;
319706f2543Smrg    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
320706f2543Smrg    DRIContextFlags	flags    = 0;
321706f2543Smrg    DRIContextPrivPtr	pDRIContextPriv;
322706f2543Smrg
323706f2543Smrg    /* If the DRI extension is disabled, do not initialize the DRI */
324706f2543Smrg    if (noXFree86DRIExtension) {
325706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_WARNING,
326706f2543Smrg		  "Direct rendering has been disabled.\n");
327706f2543Smrg	return FALSE;
328706f2543Smrg    }
329706f2543Smrg
330706f2543Smrg    if (!xf86VGAarbiterAllowDRI(pScreen)) {
331706f2543Smrg        DRIDrvMsg(pScreen->myNum, X_WARNING,
332706f2543Smrg                  "Direct rendering is not supported when VGA arb is necessary for the device\n");
333706f2543Smrg	return FALSE;
334706f2543Smrg    }
335706f2543Smrg
336706f2543Smrg#ifdef PANORAMIX
337706f2543Smrg    /*
338706f2543Smrg     * If Xinerama is on, don't allow DRI to initialise.  It won't be usable
339706f2543Smrg     * anyway.
340706f2543Smrg     */
341706f2543Smrg	if (!noPanoramiXExtension) {
342706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_WARNING,
343706f2543Smrg		"Direct rendering is not supported when Xinerama is enabled\n");
344706f2543Smrg	    return FALSE;
345706f2543Smrg	}
346706f2543Smrg#endif
347706f2543Smrg
348706f2543Smrg    if (!DRIOpenDRMMaster(pScrn, pDRIInfo->SAREASize,
349706f2543Smrg			  pDRIInfo->busIdString,
350706f2543Smrg			  pDRIInfo->drmDriverName))
351706f2543Smrg	return FALSE;
352706f2543Smrg
353706f2543Smrg    pDRIEntPriv = DRI_ENT_PRIV(pScrn);
354706f2543Smrg
355706f2543Smrg    if (DRIGeneration != serverGeneration)
356706f2543Smrg	DRIGeneration = serverGeneration;
357706f2543Smrg
358706f2543Smrg    if (!dixRegisterPrivateKey(&DRIScreenPrivKeyRec, PRIVATE_SCREEN, 0))
359706f2543Smrg	return FALSE;
360706f2543Smrg    if (!dixRegisterPrivateKey(&DRIWindowPrivKeyRec, PRIVATE_WINDOW, 0))
361706f2543Smrg	return FALSE;
362706f2543Smrg
363706f2543Smrg    pDRIPriv = (DRIScreenPrivPtr) calloc(1, sizeof(DRIScreenPrivRec));
364706f2543Smrg    if (!pDRIPriv) {
365706f2543Smrg	dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
366706f2543Smrg        return FALSE;
367706f2543Smrg    }
368706f2543Smrg
369706f2543Smrg    dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv);
370706f2543Smrg    pDRIPriv->drmFD = pDRIEntPriv->drmFD;
371706f2543Smrg    pDRIPriv->directRenderingSupport = TRUE;
372706f2543Smrg    pDRIPriv->pDriverInfo = pDRIInfo;
373706f2543Smrg    pDRIPriv->nrWindows = 0;
374706f2543Smrg    pDRIPriv->nrWindowsVisible = 0;
375706f2543Smrg    pDRIPriv->fullscreen = NULL;
376706f2543Smrg
377706f2543Smrg    pDRIPriv->createDummyCtx     = pDRIInfo->createDummyCtx;
378706f2543Smrg    pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv;
379706f2543Smrg
380706f2543Smrg    pDRIPriv->grabbedDRILock = FALSE;
381706f2543Smrg    pDRIPriv->drmSIGIOHandlerInstalled = FALSE;
382706f2543Smrg    *pDRMFD = pDRIPriv->drmFD;
383706f2543Smrg
384706f2543Smrg    if (pDRIEntPriv->sAreaGrabbed || pDRIInfo->allocSarea) {
385706f2543Smrg
386706f2543Smrg	if (drmAddMap( pDRIPriv->drmFD,
387706f2543Smrg		       0,
388706f2543Smrg		       pDRIPriv->pDriverInfo->SAREASize,
389706f2543Smrg		       DRM_SHM,
390706f2543Smrg		       0,
391706f2543Smrg		       &pDRIPriv->hSAREA) < 0)
392706f2543Smrg	{
393706f2543Smrg	    pDRIPriv->directRenderingSupport = FALSE;
394706f2543Smrg	    dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
395706f2543Smrg	    drmClose(pDRIPriv->drmFD);
396706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_INFO,
397706f2543Smrg		      "[drm] drmAddMap failed\n");
398706f2543Smrg	    return FALSE;
399706f2543Smrg	}
400706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_INFO,
401706f2543Smrg		  "[drm] added %d byte SAREA at %p\n",
402706f2543Smrg		  pDRIPriv->pDriverInfo->SAREASize, pDRIPriv->hSAREA);
403706f2543Smrg
404706f2543Smrg	/* Backwards compat. */
405706f2543Smrg	if (drmMap( pDRIPriv->drmFD,
406706f2543Smrg		    pDRIPriv->hSAREA,
407706f2543Smrg		    pDRIPriv->pDriverInfo->SAREASize,
408706f2543Smrg		    (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0)
409706f2543Smrg	{
410706f2543Smrg	    pDRIPriv->directRenderingSupport = FALSE;
411706f2543Smrg	    dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
412706f2543Smrg	    drmClose(pDRIPriv->drmFD);
413706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_INFO,
414706f2543Smrg		      "[drm] drmMap failed\n");
415706f2543Smrg	    return FALSE;
416706f2543Smrg	}
417706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n",
418706f2543Smrg		  pDRIPriv->hSAREA, pDRIPriv->pSAREA);
419706f2543Smrg	memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize);
420706f2543Smrg    } else {
421706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Using the DRM lock "
422706f2543Smrg		  "SAREA also for drawables.\n");
423706f2543Smrg	pDRIPriv->hSAREA = pDRIEntPriv->hLSAREA;
424706f2543Smrg	pDRIPriv->pSAREA = (XF86DRISAREAPtr) pDRIEntPriv->pLSAREA;
425706f2543Smrg	pDRIEntPriv->sAreaGrabbed = TRUE;
426706f2543Smrg    }
427706f2543Smrg
428706f2543Smrg    pDRIPriv->hLSAREA = pDRIEntPriv->hLSAREA;
429706f2543Smrg    pDRIPriv->pLSAREA = pDRIEntPriv->pLSAREA;
430706f2543Smrg
431706f2543Smrg    if (!pDRIPriv->pDriverInfo->dontMapFrameBuffer)
432706f2543Smrg    {
433706f2543Smrg	if (drmAddMap( pDRIPriv->drmFD,
434706f2543Smrg		       (uintptr_t)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress,
435706f2543Smrg		       pDRIPriv->pDriverInfo->frameBufferSize,
436706f2543Smrg		       DRM_FRAME_BUFFER,
437706f2543Smrg		       0,
438706f2543Smrg		       &pDRIPriv->pDriverInfo->hFrameBuffer) < 0)
439706f2543Smrg	    {
440706f2543Smrg		pDRIPriv->directRenderingSupport = FALSE;
441706f2543Smrg		dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
442706f2543Smrg		drmUnmap(pDRIPriv->pSAREA, pDRIPriv->pDriverInfo->SAREASize);
443706f2543Smrg		drmClose(pDRIPriv->drmFD);
444706f2543Smrg		DRIDrvMsg(pScreen->myNum, X_INFO,
445706f2543Smrg			  "[drm] drmAddMap failed\n");
446706f2543Smrg		return FALSE;
447706f2543Smrg	    }
448706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = %p\n",
449706f2543Smrg		  pDRIPriv->pDriverInfo->hFrameBuffer);
450706f2543Smrg    } else {
451706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_INFO,
452706f2543Smrg		  "[drm] framebuffer mapped by ddx driver\n");
453706f2543Smrg    }
454706f2543Smrg
455706f2543Smrg    if (pDRIEntPriv->resOwner == NULL) {
456706f2543Smrg	pDRIEntPriv->resOwner = pScreen;
457706f2543Smrg
458706f2543Smrg	/* Add tags for reserved contexts */
459706f2543Smrg	if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
460706f2543Smrg						  &reserved_count))) {
461706f2543Smrg	    int  i;
462706f2543Smrg	    void *tag;
463706f2543Smrg
464706f2543Smrg	    for (i = 0; i < reserved_count; i++) {
465706f2543Smrg		tag = DRICreateContextPrivFromHandle(pScreen,
466706f2543Smrg						     reserved[i],
467706f2543Smrg						     DRI_CONTEXT_RESERVED);
468706f2543Smrg		drmAddContextTag(pDRIPriv->drmFD, reserved[i], tag);
469706f2543Smrg	    }
470706f2543Smrg	    drmFreeReservedContextList(reserved);
471706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_INFO,
472706f2543Smrg		      "[drm] added %d reserved context%s for kernel\n",
473706f2543Smrg		      reserved_count, reserved_count > 1 ? "s" : "");
474706f2543Smrg	}
475706f2543Smrg    }
476706f2543Smrg
477706f2543Smrg    /* validate max drawable table entry set by driver */
478706f2543Smrg    if ((pDRIPriv->pDriverInfo->maxDrawableTableEntry <= 0) ||
479706f2543Smrg        (pDRIPriv->pDriverInfo->maxDrawableTableEntry > SAREA_MAX_DRAWABLES)) {
480706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_ERROR,
481706f2543Smrg		      "Invalid max drawable table size set by driver: %d\n",
482706f2543Smrg		      pDRIPriv->pDriverInfo->maxDrawableTableEntry);
483706f2543Smrg    }
484706f2543Smrg
485706f2543Smrg    /* Initialize drawable tables (screen private and SAREA) */
486706f2543Smrg    for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
487706f2543Smrg	pDRIPriv->DRIDrawables[i] = NULL;
488706f2543Smrg	pDRIPriv->pSAREA->drawableTable[i].stamp = 0;
489706f2543Smrg	pDRIPriv->pSAREA->drawableTable[i].flags = 0;
490706f2543Smrg    }
491706f2543Smrg
492706f2543Smrg    pDRIPriv->pLockRefCount = &pDRIEntPriv->lockRefCount;
493706f2543Smrg    pDRIPriv->pLockingContext = &pDRIEntPriv->lockingContext;
494706f2543Smrg
495706f2543Smrg    if (!pDRIEntPriv->keepFDOpen)
496706f2543Smrg	pDRIEntPriv->keepFDOpen = pDRIInfo->keepFDOpen;
497706f2543Smrg
498706f2543Smrg    pDRIEntPriv->refCount++;
499706f2543Smrg
500706f2543Smrg    /* Set up flags for DRICreateContextPriv */
501706f2543Smrg    switch (pDRIInfo->driverSwapMethod) {
502706f2543Smrg    case DRI_KERNEL_SWAP:
503706f2543Smrg	flags = DRI_CONTEXT_2DONLY;
504706f2543Smrg	break;
505706f2543Smrg    case DRI_HIDE_X_CONTEXT:
506706f2543Smrg	flags = DRI_CONTEXT_PRESERVED;
507706f2543Smrg	break;
508706f2543Smrg    }
509706f2543Smrg
510706f2543Smrg    if (!(pDRIContextPriv = DRICreateContextPriv(pScreen,
511706f2543Smrg						 &pDRIPriv->myContext,
512706f2543Smrg						 flags))) {
513706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_ERROR,
514706f2543Smrg		  "failed to create server context\n");
515706f2543Smrg	return FALSE;
516706f2543Smrg    }
517706f2543Smrg    pDRIPriv->myContextPriv = pDRIContextPriv;
518706f2543Smrg
519706f2543Smrg    DRIDrvMsg(pScreen->myNum, X_INFO,
520706f2543Smrg	      "X context handle = %p\n", pDRIPriv->myContext);
521706f2543Smrg
522706f2543Smrg    /* Now that we have created the X server's context, we can grab the
523706f2543Smrg     * hardware lock for the X server.
524706f2543Smrg     */
525706f2543Smrg    DRILock(pScreen, 0);
526706f2543Smrg    pDRIPriv->grabbedDRILock = TRUE;
527706f2543Smrg
528706f2543Smrg    /* pointers so that we can prevent memory leaks later */
529706f2543Smrg    pDRIPriv->hiddenContextStore    = NULL;
530706f2543Smrg    pDRIPriv->partial3DContextStore = NULL;
531706f2543Smrg
532706f2543Smrg    switch(pDRIInfo->driverSwapMethod) {
533706f2543Smrg    case DRI_HIDE_X_CONTEXT:
534706f2543Smrg	/* Server will handle 3D swaps, and hide 2D swaps from kernel.
535706f2543Smrg	 * Register server context as a preserved context.
536706f2543Smrg	 */
537706f2543Smrg
538706f2543Smrg	/* allocate memory for hidden context store */
539706f2543Smrg	pDRIPriv->hiddenContextStore
540706f2543Smrg	    = (void *)calloc(1, pDRIInfo->contextSize);
541706f2543Smrg	if (!pDRIPriv->hiddenContextStore) {
542706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_ERROR,
543706f2543Smrg		      "failed to allocate hidden context\n");
544706f2543Smrg	    DRIDestroyContextPriv(pDRIContextPriv);
545706f2543Smrg	    return FALSE;
546706f2543Smrg	}
547706f2543Smrg
548706f2543Smrg	/* allocate memory for partial 3D context store */
549706f2543Smrg	pDRIPriv->partial3DContextStore
550706f2543Smrg	    = (void *)calloc(1, pDRIInfo->contextSize);
551706f2543Smrg	if (!pDRIPriv->partial3DContextStore) {
552706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_ERROR,
553706f2543Smrg		      "[DRI] failed to allocate partial 3D context\n");
554706f2543Smrg	    free(pDRIPriv->hiddenContextStore);
555706f2543Smrg	    DRIDestroyContextPriv(pDRIContextPriv);
556706f2543Smrg	    return FALSE;
557706f2543Smrg	}
558706f2543Smrg
559706f2543Smrg	/* save initial context store */
560706f2543Smrg	if (pDRIInfo->SwapContext) {
561706f2543Smrg	    (*pDRIInfo->SwapContext)(
562706f2543Smrg		pScreen,
563706f2543Smrg		DRI_NO_SYNC,
564706f2543Smrg		DRI_2D_CONTEXT,
565706f2543Smrg		pDRIPriv->hiddenContextStore,
566706f2543Smrg		DRI_NO_CONTEXT,
567706f2543Smrg		NULL);
568706f2543Smrg	}
569706f2543Smrg	/* fall through */
570706f2543Smrg
571706f2543Smrg    case DRI_SERVER_SWAP:
572706f2543Smrg        /* For swap methods of DRI_SERVER_SWAP and DRI_HIDE_X_CONTEXT
573706f2543Smrg         * setup signal handler for receiving swap requests from kernel
574706f2543Smrg	 */
575706f2543Smrg	if (!(pDRIPriv->drmSIGIOHandlerInstalled =
576706f2543Smrg	      drmInstallSIGIOHandler(pDRIPriv->drmFD, DRISwapContext))) {
577706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_ERROR,
578706f2543Smrg		      "[drm] failed to setup DRM signal handler\n");
579706f2543Smrg	    free(pDRIPriv->hiddenContextStore);
580706f2543Smrg	    free(pDRIPriv->partial3DContextStore);
581706f2543Smrg	    DRIDestroyContextPriv(pDRIContextPriv);
582706f2543Smrg	    return FALSE;
583706f2543Smrg	} else {
584706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_INFO,
585706f2543Smrg		      "[drm] installed DRM signal handler\n");
586706f2543Smrg	}
587706f2543Smrg
588706f2543Smrg    default:
589706f2543Smrg	break;
590706f2543Smrg    }
591706f2543Smrg
592706f2543Smrg    return TRUE;
593706f2543Smrg}
594706f2543Smrg
595706f2543SmrgBool
596706f2543SmrgDRIFinishScreenInit(ScreenPtr pScreen)
597706f2543Smrg{
598706f2543Smrg    DRIScreenPrivPtr  pDRIPriv = DRI_SCREEN_PRIV(pScreen);
599706f2543Smrg    DRIInfoPtr        pDRIInfo = pDRIPriv->pDriverInfo;
600706f2543Smrg
601706f2543Smrg    /* Wrap DRI support */
602706f2543Smrg    if (pDRIInfo->wrap.ValidateTree) {
603706f2543Smrg	pDRIPriv->wrap.ValidateTree     = pScreen->ValidateTree;
604706f2543Smrg	pScreen->ValidateTree           = pDRIInfo->wrap.ValidateTree;
605706f2543Smrg    }
606706f2543Smrg    if (pDRIInfo->wrap.PostValidateTree) {
607706f2543Smrg	pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
608706f2543Smrg	pScreen->PostValidateTree       = pDRIInfo->wrap.PostValidateTree;
609706f2543Smrg    }
610706f2543Smrg    if (pDRIInfo->wrap.WindowExposures) {
611706f2543Smrg	pDRIPriv->wrap.WindowExposures  = pScreen->WindowExposures;
612706f2543Smrg	pScreen->WindowExposures        = pDRIInfo->wrap.WindowExposures;
613706f2543Smrg    }
614706f2543Smrg
615706f2543Smrg    pDRIPriv->DestroyWindow             = pScreen->DestroyWindow;
616706f2543Smrg    pScreen->DestroyWindow              = DRIDestroyWindow;
617706f2543Smrg
618706f2543Smrg    pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen,
619706f2543Smrg						       dri_crtc_notify);
620706f2543Smrg
621706f2543Smrg    if (pDRIInfo->wrap.CopyWindow) {
622706f2543Smrg	pDRIPriv->wrap.CopyWindow       = pScreen->CopyWindow;
623706f2543Smrg	pScreen->CopyWindow             = pDRIInfo->wrap.CopyWindow;
624706f2543Smrg    }
625706f2543Smrg    if (pDRIInfo->wrap.ClipNotify) {
626706f2543Smrg	pDRIPriv->wrap.ClipNotify       = pScreen->ClipNotify;
627706f2543Smrg	pScreen->ClipNotify             = pDRIInfo->wrap.ClipNotify;
628706f2543Smrg    }
629706f2543Smrg    if (pDRIInfo->wrap.AdjustFrame) {
630706f2543Smrg	ScrnInfoPtr pScrn               = xf86Screens[pScreen->myNum];
631706f2543Smrg	pDRIPriv->wrap.AdjustFrame      = pScrn->AdjustFrame;
632706f2543Smrg	pScrn->AdjustFrame              = pDRIInfo->wrap.AdjustFrame;
633706f2543Smrg    }
634706f2543Smrg    pDRIPriv->wrapped = TRUE;
635706f2543Smrg
636706f2543Smrg    DRIDrvMsg(pScreen->myNum, X_INFO, "[DRI] installation complete\n");
637706f2543Smrg
638706f2543Smrg    return TRUE;
639706f2543Smrg}
640706f2543Smrg
641706f2543Smrgvoid
642706f2543SmrgDRICloseScreen(ScreenPtr pScreen)
643706f2543Smrg{
644706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
645706f2543Smrg    DRIInfoPtr       pDRIInfo;
646706f2543Smrg    drm_context_t *    reserved;
647706f2543Smrg    int              reserved_count;
648706f2543Smrg    ScrnInfoPtr      pScrn = xf86Screens[pScreen->myNum];
649706f2543Smrg    DRIEntPrivPtr    pDRIEntPriv = DRI_ENT_PRIV(pScrn);
650706f2543Smrg    Bool closeMaster;
651706f2543Smrg
652706f2543Smrg    if (pDRIPriv) {
653706f2543Smrg
654706f2543Smrg        pDRIInfo = pDRIPriv->pDriverInfo;
655706f2543Smrg
656706f2543Smrg	if (pDRIPriv->wrapped) {
657706f2543Smrg	    /* Unwrap DRI Functions */
658706f2543Smrg	    if (pDRIInfo->wrap.ValidateTree) {
659706f2543Smrg		pScreen->ValidateTree           = pDRIPriv->wrap.ValidateTree;
660706f2543Smrg		pDRIPriv->wrap.ValidateTree     = NULL;
661706f2543Smrg	    }
662706f2543Smrg	    if (pDRIInfo->wrap.PostValidateTree) {
663706f2543Smrg		pScreen->PostValidateTree       = pDRIPriv->wrap.PostValidateTree;
664706f2543Smrg		pDRIPriv->wrap.PostValidateTree = NULL;
665706f2543Smrg	    }
666706f2543Smrg	    if (pDRIInfo->wrap.WindowExposures) {
667706f2543Smrg		pScreen->WindowExposures        = pDRIPriv->wrap.WindowExposures;
668706f2543Smrg		pDRIPriv->wrap.WindowExposures  = NULL;
669706f2543Smrg	    }
670706f2543Smrg	    if (pDRIPriv->DestroyWindow) {
671706f2543Smrg		pScreen->DestroyWindow          = pDRIPriv->DestroyWindow;
672706f2543Smrg		pDRIPriv->DestroyWindow         = NULL;
673706f2543Smrg	    }
674706f2543Smrg
675706f2543Smrg	    xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify);
676706f2543Smrg
677706f2543Smrg	    if (pDRIInfo->wrap.CopyWindow) {
678706f2543Smrg		pScreen->CopyWindow             = pDRIPriv->wrap.CopyWindow;
679706f2543Smrg		pDRIPriv->wrap.CopyWindow       = NULL;
680706f2543Smrg	    }
681706f2543Smrg	    if (pDRIInfo->wrap.ClipNotify) {
682706f2543Smrg		pScreen->ClipNotify             = pDRIPriv->wrap.ClipNotify;
683706f2543Smrg		pDRIPriv->wrap.ClipNotify       = NULL;
684706f2543Smrg	    }
685706f2543Smrg	    if (pDRIInfo->wrap.AdjustFrame) {
686706f2543Smrg		ScrnInfoPtr pScrn               = xf86Screens[pScreen->myNum];
687706f2543Smrg		pScrn->AdjustFrame              = pDRIPriv->wrap.AdjustFrame;
688706f2543Smrg		pDRIPriv->wrap.AdjustFrame      = NULL;
689706f2543Smrg	    }
690706f2543Smrg
691706f2543Smrg	    pDRIPriv->wrapped = FALSE;
692706f2543Smrg	}
693706f2543Smrg
694706f2543Smrg	if (pDRIPriv->drmSIGIOHandlerInstalled) {
695706f2543Smrg	    if (!drmRemoveSIGIOHandler(pDRIPriv->drmFD)) {
696706f2543Smrg		DRIDrvMsg(pScreen->myNum, X_ERROR,
697706f2543Smrg			  "[drm] failed to remove DRM signal handler\n");
698706f2543Smrg	    }
699706f2543Smrg	}
700706f2543Smrg
701706f2543Smrg        if (pDRIPriv->dummyCtxPriv && pDRIPriv->createDummyCtx) {
702706f2543Smrg	    DRIDestroyDummyContext(pScreen, pDRIPriv->createDummyCtxPriv);
703706f2543Smrg	}
704706f2543Smrg
705706f2543Smrg	if (!DRIDestroyContextPriv(pDRIPriv->myContextPriv)) {
706706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_ERROR,
707706f2543Smrg		      "failed to destroy server context\n");
708706f2543Smrg	}
709706f2543Smrg
710706f2543Smrg				/* Remove tags for reserved contexts */
711706f2543Smrg	if (pDRIEntPriv->resOwner == pScreen) {
712706f2543Smrg	    pDRIEntPriv->resOwner = NULL;
713706f2543Smrg
714706f2543Smrg	    if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
715706f2543Smrg						  &reserved_count))) {
716706f2543Smrg		int  i;
717706f2543Smrg
718706f2543Smrg		for (i = 0; i < reserved_count; i++) {
719706f2543Smrg		    DRIDestroyContextPriv(drmGetContextTag(pDRIPriv->drmFD,
720706f2543Smrg							   reserved[i]));
721706f2543Smrg		}
722706f2543Smrg		drmFreeReservedContextList(reserved);
723706f2543Smrg		DRIDrvMsg(pScreen->myNum, X_INFO,
724706f2543Smrg			  "[drm] removed %d reserved context%s for kernel\n",
725706f2543Smrg			  reserved_count, reserved_count > 1 ? "s" : "");
726706f2543Smrg	    }
727706f2543Smrg	}
728706f2543Smrg
729706f2543Smrg	/* Make sure signals get unblocked etc. */
730706f2543Smrg	drmUnlock(pDRIPriv->drmFD, pDRIPriv->myContext);
731706f2543Smrg	pDRIPriv->pLockRefCount = NULL;
732706f2543Smrg	closeMaster = (--pDRIEntPriv->refCount == 0) &&
733706f2543Smrg	    !pDRIEntPriv->keepFDOpen;
734706f2543Smrg	if (closeMaster || pDRIPriv->hSAREA != pDRIEntPriv->hLSAREA) {
735706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_INFO,
736706f2543Smrg		      "[drm] unmapping %d bytes of SAREA %p at %p\n",
737706f2543Smrg		      pDRIInfo->SAREASize,
738706f2543Smrg		      pDRIPriv->hSAREA,
739706f2543Smrg		      pDRIPriv->pSAREA);
740706f2543Smrg	    if (drmUnmap(pDRIPriv->pSAREA, pDRIInfo->SAREASize)) {
741706f2543Smrg		DRIDrvMsg(pScreen->myNum, X_ERROR,
742706f2543Smrg			  "[drm] unable to unmap %d bytes"
743706f2543Smrg			  " of SAREA %p at %p\n",
744706f2543Smrg			  pDRIInfo->SAREASize,
745706f2543Smrg			  pDRIPriv->hSAREA,
746706f2543Smrg			  pDRIPriv->pSAREA);
747706f2543Smrg	    }
748706f2543Smrg	} else {
749706f2543Smrg	    pDRIEntPriv->sAreaGrabbed = FALSE;
750706f2543Smrg	}
751706f2543Smrg
752706f2543Smrg	if (closeMaster || (pDRIEntPriv->drmFD != pDRIPriv->drmFD)) {
753706f2543Smrg	    drmClose(pDRIPriv->drmFD);
754706f2543Smrg	    if (pDRIEntPriv->drmFD == pDRIPriv->drmFD) {
755706f2543Smrg		DRIDrvMsg(pScreen->myNum, X_INFO,
756706f2543Smrg			  "[drm] Closed DRM master.\n");
757706f2543Smrg		pDRIEntPriv->drmFD = -1;
758706f2543Smrg	    }
759706f2543Smrg	}
760706f2543Smrg
761706f2543Smrg	free(pDRIPriv);
762706f2543Smrg	dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
763706f2543Smrg    }
764706f2543Smrg}
765706f2543Smrg
766706f2543Smrg#define DRM_MSG_VERBOSITY 3
767706f2543Smrg
768706f2543Smrgstatic int dri_drm_debug_print(const char *format, va_list ap)
769706f2543Smrg{
770706f2543Smrg  xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap);
771706f2543Smrg  return 0;
772706f2543Smrg}
773706f2543Smrg
774706f2543Smrgstatic void dri_drm_get_perms(gid_t *group, mode_t *mode)
775706f2543Smrg{
776706f2543Smrg  *group = xf86ConfigDRI.group;
777706f2543Smrg  *mode = xf86ConfigDRI.mode;
778706f2543Smrg}
779706f2543Smrg
780706f2543SmrgdrmServerInfo DRIDRMServerInfo =  {
781706f2543Smrg  dri_drm_debug_print,
782706f2543Smrg  xf86LoadKernelModule,
783706f2543Smrg  dri_drm_get_perms,
784706f2543Smrg};
785706f2543Smrg
786706f2543SmrgBool
787706f2543SmrgDRIExtensionInit(void)
788706f2543Smrg{
789706f2543Smrg    if (DRIGeneration != serverGeneration) {
790706f2543Smrg	return FALSE;
791706f2543Smrg    }
792706f2543Smrg
793706f2543Smrg    DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete,
794706f2543Smrg						   "DRIDrawable");
795706f2543Smrg    DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete,
796706f2543Smrg						  "DRIContext");
797706f2543Smrg
798706f2543Smrg    if (!DRIDrawablePrivResType || !DRIContextPrivResType)
799706f2543Smrg	return FALSE;
800706f2543Smrg
801706f2543Smrg    RegisterBlockAndWakeupHandlers(DRIBlockHandler, DRIWakeupHandler, NULL);
802706f2543Smrg
803706f2543Smrg    return TRUE;
804706f2543Smrg}
805706f2543Smrg
806706f2543Smrgvoid
807706f2543SmrgDRIReset(void)
808706f2543Smrg{
809706f2543Smrg    /*
810706f2543Smrg     * This stub routine is called when the X Server recycles, resources
811706f2543Smrg     * allocated by DRIExtensionInit need to be managed here.
812706f2543Smrg     *
813706f2543Smrg     * Currently this routine is a stub because all the interesting resources
814706f2543Smrg     * are managed via the screen init process.
815706f2543Smrg     */
816706f2543Smrg}
817706f2543Smrg
818706f2543SmrgBool
819706f2543SmrgDRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable)
820706f2543Smrg{
821706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
822706f2543Smrg
823706f2543Smrg    if (pDRIPriv)
824706f2543Smrg	*isCapable = pDRIPriv->directRenderingSupport;
825706f2543Smrg    else
826706f2543Smrg	*isCapable = FALSE;
827706f2543Smrg
828706f2543Smrg    return TRUE;
829706f2543Smrg}
830706f2543Smrg
831706f2543SmrgBool
832706f2543SmrgDRIOpenConnection(ScreenPtr pScreen, drm_handle_t * hSAREA, char **busIdString)
833706f2543Smrg{
834706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
835706f2543Smrg
836706f2543Smrg    *hSAREA           = pDRIPriv->hSAREA;
837706f2543Smrg    *busIdString      = pDRIPriv->pDriverInfo->busIdString;
838706f2543Smrg
839706f2543Smrg    return TRUE;
840706f2543Smrg}
841706f2543Smrg
842706f2543SmrgBool
843706f2543SmrgDRIAuthConnection(ScreenPtr pScreen, drm_magic_t magic)
844706f2543Smrg{
845706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
846706f2543Smrg
847706f2543Smrg    if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE;
848706f2543Smrg    return TRUE;
849706f2543Smrg}
850706f2543Smrg
851706f2543SmrgBool
852706f2543SmrgDRICloseConnection(ScreenPtr pScreen)
853706f2543Smrg{
854706f2543Smrg    return TRUE;
855706f2543Smrg}
856706f2543Smrg
857706f2543SmrgBool
858706f2543SmrgDRIGetClientDriverName(ScreenPtr pScreen,
859706f2543Smrg                       int *ddxDriverMajorVersion,
860706f2543Smrg                       int *ddxDriverMinorVersion,
861706f2543Smrg                       int *ddxDriverPatchVersion,
862706f2543Smrg                       char **clientDriverName)
863706f2543Smrg{
864706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
865706f2543Smrg
866706f2543Smrg    *ddxDriverMajorVersion = pDRIPriv->pDriverInfo->ddxDriverMajorVersion;
867706f2543Smrg    *ddxDriverMinorVersion = pDRIPriv->pDriverInfo->ddxDriverMinorVersion;
868706f2543Smrg    *ddxDriverPatchVersion = pDRIPriv->pDriverInfo->ddxDriverPatchVersion;
869706f2543Smrg    *clientDriverName      = pDRIPriv->pDriverInfo->clientDriverName;
870706f2543Smrg
871706f2543Smrg    return TRUE;
872706f2543Smrg}
873706f2543Smrg
874706f2543Smrg/* DRICreateContextPriv and DRICreateContextPrivFromHandle are helper
875706f2543Smrg   functions that layer on drmCreateContext and drmAddContextTag.
876706f2543Smrg
877706f2543Smrg   DRICreateContextPriv always creates a kernel drm_context_t and then calls
878706f2543Smrg   DRICreateContextPrivFromHandle to create a DRIContextPriv structure for
879706f2543Smrg   DRI tracking.  For the SIGIO handler, the drm_context_t is associated with
880706f2543Smrg   DRIContextPrivPtr.  Any special flags are stored in the DRIContextPriv
881706f2543Smrg   area and are passed to the kernel (if necessary).
882706f2543Smrg
883706f2543Smrg   DRICreateContextPriv returns a pointer to newly allocated
884706f2543Smrg   DRIContextPriv, and returns the kernel drm_context_t in pHWContext. */
885706f2543Smrg
886706f2543SmrgDRIContextPrivPtr
887706f2543SmrgDRICreateContextPriv(ScreenPtr pScreen,
888706f2543Smrg		     drm_context_t * pHWContext,
889706f2543Smrg		     DRIContextFlags flags)
890706f2543Smrg{
891706f2543Smrg    DRIScreenPrivPtr  pDRIPriv = DRI_SCREEN_PRIV(pScreen);
892706f2543Smrg
893706f2543Smrg    if (drmCreateContext(pDRIPriv->drmFD, pHWContext)) {
894706f2543Smrg	return NULL;
895706f2543Smrg    }
896706f2543Smrg
897706f2543Smrg    return DRICreateContextPrivFromHandle(pScreen, *pHWContext, flags);
898706f2543Smrg}
899706f2543Smrg
900706f2543SmrgDRIContextPrivPtr
901706f2543SmrgDRICreateContextPrivFromHandle(ScreenPtr pScreen,
902706f2543Smrg			       drm_context_t hHWContext,
903706f2543Smrg			       DRIContextFlags flags)
904706f2543Smrg{
905706f2543Smrg    DRIScreenPrivPtr  pDRIPriv = DRI_SCREEN_PRIV(pScreen);
906706f2543Smrg    DRIContextPrivPtr pDRIContextPriv;
907706f2543Smrg    int 	      contextPrivSize;
908706f2543Smrg
909706f2543Smrg    contextPrivSize = sizeof(DRIContextPrivRec) +
910706f2543Smrg			    pDRIPriv->pDriverInfo->contextSize;
911706f2543Smrg    if (!(pDRIContextPriv = calloc(1, contextPrivSize))) {
912706f2543Smrg	return NULL;
913706f2543Smrg    }
914706f2543Smrg    pDRIContextPriv->pContextStore = (void *)(pDRIContextPriv + 1);
915706f2543Smrg
916706f2543Smrg    drmAddContextTag(pDRIPriv->drmFD, hHWContext, pDRIContextPriv);
917706f2543Smrg
918706f2543Smrg    pDRIContextPriv->hwContext = hHWContext;
919706f2543Smrg    pDRIContextPriv->pScreen   = pScreen;
920706f2543Smrg    pDRIContextPriv->flags     = flags;
921706f2543Smrg    pDRIContextPriv->valid3D   = FALSE;
922706f2543Smrg
923706f2543Smrg    if (flags & DRI_CONTEXT_2DONLY) {
924706f2543Smrg	if (drmSetContextFlags(pDRIPriv->drmFD,
925706f2543Smrg			       hHWContext,
926706f2543Smrg			       DRM_CONTEXT_2DONLY)) {
927706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_ERROR,
928706f2543Smrg		      "[drm] failed to set 2D context flag\n");
929706f2543Smrg	    DRIDestroyContextPriv(pDRIContextPriv);
930706f2543Smrg	    return NULL;
931706f2543Smrg	}
932706f2543Smrg    }
933706f2543Smrg    if (flags & DRI_CONTEXT_PRESERVED) {
934706f2543Smrg	if (drmSetContextFlags(pDRIPriv->drmFD,
935706f2543Smrg			       hHWContext,
936706f2543Smrg			       DRM_CONTEXT_PRESERVED)) {
937706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_ERROR,
938706f2543Smrg		      "[drm] failed to set preserved flag\n");
939706f2543Smrg	    DRIDestroyContextPriv(pDRIContextPriv);
940706f2543Smrg	    return NULL;
941706f2543Smrg	}
942706f2543Smrg    }
943706f2543Smrg    return pDRIContextPriv;
944706f2543Smrg}
945706f2543Smrg
946706f2543SmrgBool
947706f2543SmrgDRIDestroyContextPriv(DRIContextPrivPtr pDRIContextPriv)
948706f2543Smrg{
949706f2543Smrg    DRIScreenPrivPtr pDRIPriv;
950706f2543Smrg
951706f2543Smrg    if (!pDRIContextPriv) return TRUE;
952706f2543Smrg
953706f2543Smrg    pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen);
954706f2543Smrg
955706f2543Smrg    if (!(pDRIContextPriv->flags & DRI_CONTEXT_RESERVED)) {
956706f2543Smrg				/* Don't delete reserved contexts from
957706f2543Smrg                                   kernel area -- the kernel manages its
958706f2543Smrg                                   reserved contexts itself. */
959706f2543Smrg	if (drmDestroyContext(pDRIPriv->drmFD, pDRIContextPriv->hwContext))
960706f2543Smrg	    return FALSE;
961706f2543Smrg    }
962706f2543Smrg
963706f2543Smrg				/* Remove the tag last to prevent a race
964706f2543Smrg                                   condition where the context has pending
965706f2543Smrg                                   buffers.  The context can't be re-used
966706f2543Smrg                                   while in this thread, but buffers can be
967706f2543Smrg                                   dispatched asynchronously. */
968706f2543Smrg    drmDelContextTag(pDRIPriv->drmFD, pDRIContextPriv->hwContext);
969706f2543Smrg    free(pDRIContextPriv);
970706f2543Smrg    return TRUE;
971706f2543Smrg}
972706f2543Smrg
973706f2543Smrgstatic Bool
974706f2543SmrgDRICreateDummyContext(ScreenPtr pScreen, Bool needCtxPriv)
975706f2543Smrg{
976706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
977706f2543Smrg    DRIContextPrivPtr pDRIContextPriv;
978706f2543Smrg    void *contextStore;
979706f2543Smrg
980706f2543Smrg    if (!(pDRIContextPriv =
981706f2543Smrg	  DRICreateContextPriv(pScreen,
982706f2543Smrg			       &pDRIPriv->pSAREA->dummy_context, 0))) {
983706f2543Smrg	return FALSE;
984706f2543Smrg    }
985706f2543Smrg
986706f2543Smrg    contextStore = DRIGetContextStore(pDRIContextPriv);
987706f2543Smrg    if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) {
988706f2543Smrg	if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, NULL,
989706f2543Smrg						  pDRIPriv->pSAREA->dummy_context,
990706f2543Smrg						  NULL,
991706f2543Smrg						  (DRIContextType)(long)contextStore)) {
992706f2543Smrg	    DRIDestroyContextPriv(pDRIContextPriv);
993706f2543Smrg	    return FALSE;
994706f2543Smrg	}
995706f2543Smrg    }
996706f2543Smrg
997706f2543Smrg    pDRIPriv->dummyCtxPriv = pDRIContextPriv;
998706f2543Smrg    return TRUE;
999706f2543Smrg}
1000706f2543Smrg
1001706f2543Smrgstatic void
1002706f2543SmrgDRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv)
1003706f2543Smrg{
1004706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1005706f2543Smrg    DRIContextPrivPtr pDRIContextPriv = pDRIPriv->dummyCtxPriv;
1006706f2543Smrg    void *contextStore;
1007706f2543Smrg
1008706f2543Smrg    if (!pDRIContextPriv) return;
1009706f2543Smrg    if (pDRIPriv->pDriverInfo->DestroyContext && hasCtxPriv) {
1010706f2543Smrg	contextStore = DRIGetContextStore(pDRIContextPriv);
1011706f2543Smrg	pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
1012706f2543Smrg					      pDRIContextPriv->hwContext,
1013706f2543Smrg					      (DRIContextType)(long)contextStore);
1014706f2543Smrg    }
1015706f2543Smrg
1016706f2543Smrg    DRIDestroyContextPriv(pDRIPriv->dummyCtxPriv);
1017706f2543Smrg    pDRIPriv->dummyCtxPriv = NULL;
1018706f2543Smrg}
1019706f2543Smrg
1020706f2543SmrgBool
1021706f2543SmrgDRICreateContext(ScreenPtr pScreen, VisualPtr visual,
1022706f2543Smrg                 XID context, drm_context_t * pHWContext)
1023706f2543Smrg{
1024706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1025706f2543Smrg    DRIContextPrivPtr pDRIContextPriv;
1026706f2543Smrg    void *contextStore;
1027706f2543Smrg
1028706f2543Smrg    if (pDRIPriv->createDummyCtx && !pDRIPriv->dummyCtxPriv) {
1029706f2543Smrg        if (!DRICreateDummyContext(pScreen, pDRIPriv->createDummyCtxPriv)) {
1030706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_INFO,
1031706f2543Smrg		      "[drm] Could not create dummy context\n");
1032706f2543Smrg	    return FALSE;
1033706f2543Smrg	}
1034706f2543Smrg    }
1035706f2543Smrg
1036706f2543Smrg    if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) {
1037706f2543Smrg	return FALSE;
1038706f2543Smrg    }
1039706f2543Smrg
1040706f2543Smrg    contextStore = DRIGetContextStore(pDRIContextPriv);
1041706f2543Smrg    if (pDRIPriv->pDriverInfo->CreateContext) {
1042706f2543Smrg	if (!((*pDRIPriv->pDriverInfo->CreateContext)(pScreen, NULL,
1043706f2543Smrg		*pHWContext, NULL,
1044706f2543Smrg		(DRIContextType)(long)contextStore))) {
1045706f2543Smrg	    DRIDestroyContextPriv(pDRIContextPriv);
1046706f2543Smrg	    return FALSE;
1047706f2543Smrg	}
1048706f2543Smrg    }
1049706f2543Smrg
1050706f2543Smrg    /* track this in case the client dies before cleanup */
1051706f2543Smrg    AddResource(context, DRIContextPrivResType, (pointer)pDRIContextPriv);
1052706f2543Smrg
1053706f2543Smrg    return TRUE;
1054706f2543Smrg}
1055706f2543Smrg
1056706f2543SmrgBool
1057706f2543SmrgDRIDestroyContext(ScreenPtr pScreen, XID context)
1058706f2543Smrg{
1059706f2543Smrg    FreeResourceByType(context, DRIContextPrivResType, FALSE);
1060706f2543Smrg
1061706f2543Smrg    return TRUE;
1062706f2543Smrg}
1063706f2543Smrg
1064706f2543Smrg/* DRIContextPrivDelete is called by the resource manager. */
1065706f2543SmrgBool
1066706f2543SmrgDRIContextPrivDelete(pointer pResource, XID id)
1067706f2543Smrg{
1068706f2543Smrg    DRIContextPrivPtr pDRIContextPriv = (DRIContextPrivPtr)pResource;
1069706f2543Smrg    DRIScreenPrivPtr pDRIPriv;
1070706f2543Smrg    void *contextStore;
1071706f2543Smrg
1072706f2543Smrg    pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen);
1073706f2543Smrg    if (pDRIPriv->pDriverInfo->DestroyContext) {
1074706f2543Smrg      contextStore = DRIGetContextStore(pDRIContextPriv);
1075706f2543Smrg      pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen,
1076706f2543Smrg					    pDRIContextPriv->hwContext,
1077706f2543Smrg					    (DRIContextType)(long)contextStore);
1078706f2543Smrg    }
1079706f2543Smrg    return DRIDestroyContextPriv(pDRIContextPriv);
1080706f2543Smrg}
1081706f2543Smrg
1082706f2543Smrg
1083706f2543Smrg/* This walks the drawable timestamp array and invalidates all of them
1084706f2543Smrg * in the case of transition from private to shared backbuffers.  It's
1085706f2543Smrg * not necessary for correctness, because DRIClipNotify gets called in
1086706f2543Smrg * time to prevent any conflict, but the transition from
1087706f2543Smrg * shared->private is sometimes missed if we don't do this.
1088706f2543Smrg */
1089706f2543Smrgstatic void
1090706f2543SmrgDRIClipNotifyAllDrawables(ScreenPtr pScreen)
1091706f2543Smrg{
1092706f2543Smrg   int i;
1093706f2543Smrg   DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1094706f2543Smrg
1095706f2543Smrg   for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) {
1096706f2543Smrg      pDRIPriv->pSAREA->drawableTable[i].stamp = DRIDrawableValidationStamp++;
1097706f2543Smrg   }
1098706f2543Smrg}
1099706f2543Smrg
1100706f2543Smrg
1101706f2543Smrgstatic void
1102706f2543SmrgDRITransitionToSharedBuffers(ScreenPtr pScreen)
1103706f2543Smrg{
1104706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1105706f2543Smrg    DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
1106706f2543Smrg
1107706f2543Smrg    DRIClipNotifyAllDrawables( pScreen );
1108706f2543Smrg
1109706f2543Smrg    if (pDRIInfo->TransitionSingleToMulti3D)
1110706f2543Smrg	pDRIInfo->TransitionSingleToMulti3D( pScreen );
1111706f2543Smrg}
1112706f2543Smrg
1113706f2543Smrg
1114706f2543Smrgstatic void
1115706f2543SmrgDRITransitionToPrivateBuffers(ScreenPtr pScreen)
1116706f2543Smrg{
1117706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1118706f2543Smrg    DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
1119706f2543Smrg
1120706f2543Smrg    DRIClipNotifyAllDrawables( pScreen );
1121706f2543Smrg
1122706f2543Smrg    if (pDRIInfo->TransitionMultiToSingle3D)
1123706f2543Smrg	pDRIInfo->TransitionMultiToSingle3D( pScreen );
1124706f2543Smrg}
1125706f2543Smrg
1126706f2543Smrg
1127706f2543Smrgstatic void
1128706f2543SmrgDRITransitionTo3d(ScreenPtr pScreen)
1129706f2543Smrg{
1130706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1131706f2543Smrg    DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
1132706f2543Smrg
1133706f2543Smrg    DRIClipNotifyAllDrawables( pScreen );
1134706f2543Smrg
1135706f2543Smrg    if (pDRIInfo->TransitionTo3d)
1136706f2543Smrg	pDRIInfo->TransitionTo3d( pScreen );
1137706f2543Smrg}
1138706f2543Smrg
1139706f2543Smrgstatic void
1140706f2543SmrgDRITransitionTo2d(ScreenPtr pScreen)
1141706f2543Smrg{
1142706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1143706f2543Smrg    DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
1144706f2543Smrg
1145706f2543Smrg    DRIClipNotifyAllDrawables( pScreen );
1146706f2543Smrg
1147706f2543Smrg    if (pDRIInfo->TransitionTo2d)
1148706f2543Smrg	pDRIInfo->TransitionTo2d( pScreen );
1149706f2543Smrg}
1150706f2543Smrg
1151706f2543Smrg
1152706f2543Smrgstatic int
1153706f2543SmrgDRIDCNTreeTraversal(WindowPtr pWin, pointer data)
1154706f2543Smrg{
1155706f2543Smrg    DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
1156706f2543Smrg
1157706f2543Smrg    if (pDRIDrawablePriv) {
1158706f2543Smrg	ScreenPtr pScreen = pWin->drawable.pScreen;
1159706f2543Smrg	DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1160706f2543Smrg
1161706f2543Smrg	if (RegionNumRects(&pWin->clipList) > 0) {
1162706f2543Smrg	    WindowPtr *pDRIWindows = (WindowPtr*)data;
1163706f2543Smrg	    int i = 0;
1164706f2543Smrg
1165706f2543Smrg	    while (pDRIWindows[i])
1166706f2543Smrg		i++;
1167706f2543Smrg
1168706f2543Smrg	    pDRIWindows[i] = pWin;
1169706f2543Smrg
1170706f2543Smrg	    pDRIPriv->nrWalked++;
1171706f2543Smrg	}
1172706f2543Smrg
1173706f2543Smrg	if (pDRIPriv->nrWindows == pDRIPriv->nrWalked)
1174706f2543Smrg	    return WT_STOPWALKING;
1175706f2543Smrg    }
1176706f2543Smrg
1177706f2543Smrg    return WT_WALKCHILDREN;
1178706f2543Smrg}
1179706f2543Smrg
1180706f2543Smrgstatic void
1181706f2543SmrgDRIDriverClipNotify(ScreenPtr pScreen)
1182706f2543Smrg{
1183706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1184706f2543Smrg
1185706f2543Smrg    if (pDRIPriv->pDriverInfo->ClipNotify) {
1186706f2543Smrg	WindowPtr *pDRIWindows = calloc(sizeof(WindowPtr), pDRIPriv->nrWindows);
1187706f2543Smrg	DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo;
1188706f2543Smrg
1189706f2543Smrg	if (pDRIPriv->nrWindows > 0) {
1190706f2543Smrg	    pDRIPriv->nrWalked = 0;
1191706f2543Smrg	    TraverseTree(pScreen->root, DRIDCNTreeTraversal,
1192706f2543Smrg			 (pointer)pDRIWindows);
1193706f2543Smrg	}
1194706f2543Smrg
1195706f2543Smrg	pDRIInfo->ClipNotify(pScreen, pDRIWindows, pDRIPriv->nrWindows);
1196706f2543Smrg
1197706f2543Smrg	free(pDRIWindows);
1198706f2543Smrg    }
1199706f2543Smrg}
1200706f2543Smrg
1201706f2543Smrgstatic void
1202706f2543SmrgDRIIncreaseNumberVisible(ScreenPtr pScreen)
1203706f2543Smrg{
1204706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1205706f2543Smrg
1206706f2543Smrg    switch (++pDRIPriv->nrWindowsVisible) {
1207706f2543Smrg    case 1:
1208706f2543Smrg	DRITransitionTo3d( pScreen );
1209706f2543Smrg	break;
1210706f2543Smrg    case 2:
1211706f2543Smrg	DRITransitionToSharedBuffers( pScreen );
1212706f2543Smrg	break;
1213706f2543Smrg    default:
1214706f2543Smrg	break;
1215706f2543Smrg    }
1216706f2543Smrg
1217706f2543Smrg    DRIDriverClipNotify(pScreen);
1218706f2543Smrg}
1219706f2543Smrg
1220706f2543Smrgstatic void
1221706f2543SmrgDRIDecreaseNumberVisible(ScreenPtr pScreen)
1222706f2543Smrg{
1223706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1224706f2543Smrg
1225706f2543Smrg    switch (--pDRIPriv->nrWindowsVisible) {
1226706f2543Smrg    case 0:
1227706f2543Smrg	DRITransitionTo2d( pScreen );
1228706f2543Smrg	break;
1229706f2543Smrg    case 1:
1230706f2543Smrg	DRITransitionToPrivateBuffers( pScreen );
1231706f2543Smrg	break;
1232706f2543Smrg    default:
1233706f2543Smrg	break;
1234706f2543Smrg    }
1235706f2543Smrg
1236706f2543Smrg    DRIDriverClipNotify(pScreen);
1237706f2543Smrg}
1238706f2543Smrg
1239706f2543SmrgBool
1240706f2543SmrgDRICreateDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable,
1241706f2543Smrg		  drm_drawable_t * hHWDrawable)
1242706f2543Smrg{
1243706f2543Smrg    DRIScreenPrivPtr	pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1244706f2543Smrg    DRIDrawablePrivPtr	pDRIDrawablePriv;
1245706f2543Smrg    WindowPtr		pWin;
1246706f2543Smrg
1247706f2543Smrg    if (pDrawable->type == DRAWABLE_WINDOW) {
1248706f2543Smrg	pWin = (WindowPtr)pDrawable;
1249706f2543Smrg	if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
1250706f2543Smrg	    pDRIDrawablePriv->refCount++;
1251706f2543Smrg
1252706f2543Smrg	    if (!pDRIDrawablePriv->hwDrawable) {
1253706f2543Smrg		drmCreateDrawable(pDRIPriv->drmFD, &pDRIDrawablePriv->hwDrawable);
1254706f2543Smrg	    }
1255706f2543Smrg	}
1256706f2543Smrg	else {
1257706f2543Smrg	    /* allocate a DRI Window Private record */
1258706f2543Smrg	    if (!(pDRIDrawablePriv = malloc(sizeof(DRIDrawablePrivRec)))) {
1259706f2543Smrg		return FALSE;
1260706f2543Smrg	    }
1261706f2543Smrg
1262706f2543Smrg	    /* Only create a drm_drawable_t once */
1263706f2543Smrg	    if (drmCreateDrawable(pDRIPriv->drmFD,
1264706f2543Smrg				  &pDRIDrawablePriv->hwDrawable)) {
1265706f2543Smrg		free(pDRIDrawablePriv);
1266706f2543Smrg		return FALSE;
1267706f2543Smrg	    }
1268706f2543Smrg
1269706f2543Smrg	    /* add it to the list of DRI drawables for this screen */
1270706f2543Smrg	    pDRIDrawablePriv->pScreen = pScreen;
1271706f2543Smrg	    pDRIDrawablePriv->refCount = 1;
1272706f2543Smrg	    pDRIDrawablePriv->drawableIndex = -1;
1273706f2543Smrg	    pDRIDrawablePriv->nrects = RegionNumRects(&pWin->clipList);
1274706f2543Smrg
1275706f2543Smrg	    /* save private off of preallocated index */
1276706f2543Smrg	    dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey,
1277706f2543Smrg			  pDRIDrawablePriv);
1278706f2543Smrg	    pDRIPriv->nrWindows++;
1279706f2543Smrg
1280706f2543Smrg	    if (pDRIDrawablePriv->nrects)
1281706f2543Smrg		DRIIncreaseNumberVisible(pScreen);
1282706f2543Smrg	}
1283706f2543Smrg
1284706f2543Smrg	/* track this in case the client dies */
1285706f2543Smrg	AddResource(FakeClientID(client->index), DRIDrawablePrivResType,
1286706f2543Smrg		    (pointer)(intptr_t)pDrawable->id);
1287706f2543Smrg
1288706f2543Smrg	if (pDRIDrawablePriv->hwDrawable) {
1289706f2543Smrg	    drmUpdateDrawableInfo(pDRIPriv->drmFD,
1290706f2543Smrg				  pDRIDrawablePriv->hwDrawable,
1291706f2543Smrg				  DRM_DRAWABLE_CLIPRECTS,
1292706f2543Smrg				  RegionNumRects(&pWin->clipList),
1293706f2543Smrg				  RegionRects(&pWin->clipList));
1294706f2543Smrg	    *hHWDrawable = pDRIDrawablePriv->hwDrawable;
1295706f2543Smrg	}
1296706f2543Smrg    }
1297706f2543Smrg    else if (pDrawable->type != DRAWABLE_PIXMAP) { /* PBuffer */
1298706f2543Smrg	/* NOT_DONE */
1299706f2543Smrg	return FALSE;
1300706f2543Smrg    }
1301706f2543Smrg
1302706f2543Smrg    return TRUE;
1303706f2543Smrg}
1304706f2543Smrg
1305706f2543Smrgstatic void
1306706f2543SmrgDRIDrawablePrivDestroy(WindowPtr pWin)
1307706f2543Smrg{
1308706f2543Smrg    DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
1309706f2543Smrg    ScreenPtr pScreen;
1310706f2543Smrg    DRIScreenPrivPtr pDRIPriv;
1311706f2543Smrg
1312706f2543Smrg    if (!pDRIDrawablePriv)
1313706f2543Smrg	return;
1314706f2543Smrg
1315706f2543Smrg    pScreen = pWin->drawable.pScreen;
1316706f2543Smrg    pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1317706f2543Smrg
1318706f2543Smrg    if (pDRIDrawablePriv->drawableIndex != -1) {
1319706f2543Smrg	/* bump stamp to force outstanding 3D requests to resync */
1320706f2543Smrg	pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
1321706f2543Smrg	    = DRIDrawableValidationStamp++;
1322706f2543Smrg
1323706f2543Smrg	/* release drawable table entry */
1324706f2543Smrg	pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL;
1325706f2543Smrg    }
1326706f2543Smrg
1327706f2543Smrg    pDRIPriv->nrWindows--;
1328706f2543Smrg
1329706f2543Smrg    if (pDRIDrawablePriv->nrects)
1330706f2543Smrg	DRIDecreaseNumberVisible(pScreen);
1331706f2543Smrg
1332706f2543Smrg    drmDestroyDrawable(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable);
1333706f2543Smrg
1334706f2543Smrg    free(pDRIDrawablePriv);
1335706f2543Smrg    dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL);
1336706f2543Smrg}
1337706f2543Smrg
1338706f2543Smrgstatic Bool
1339706f2543SmrgDRIDestroyDrawableCB(pointer value, XID id, pointer data)
1340706f2543Smrg{
1341706f2543Smrg    if (value == data) {
1342706f2543Smrg	/* This calls back DRIDrawablePrivDelete which frees private area */
1343706f2543Smrg	FreeResourceByType(id, DRIDrawablePrivResType, FALSE);
1344706f2543Smrg
1345706f2543Smrg	return TRUE;
1346706f2543Smrg    }
1347706f2543Smrg
1348706f2543Smrg    return FALSE;
1349706f2543Smrg}
1350706f2543Smrg
1351706f2543SmrgBool
1352706f2543SmrgDRIDestroyDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable)
1353706f2543Smrg{
1354706f2543Smrg    if (pDrawable->type == DRAWABLE_WINDOW) {
1355706f2543Smrg	LookupClientResourceComplex(client, DRIDrawablePrivResType,
1356706f2543Smrg				    DRIDestroyDrawableCB,
1357706f2543Smrg				    (pointer)(intptr_t)pDrawable->id);
1358706f2543Smrg    }
1359706f2543Smrg    else { /* pixmap (or for GLX 1.3, a PBuffer) */
1360706f2543Smrg	/* NOT_DONE */
1361706f2543Smrg	return FALSE;
1362706f2543Smrg    }
1363706f2543Smrg
1364706f2543Smrg    return TRUE;
1365706f2543Smrg}
1366706f2543Smrg
1367706f2543SmrgBool
1368706f2543SmrgDRIDrawablePrivDelete(pointer pResource, XID id)
1369706f2543Smrg{
1370706f2543Smrg    WindowPtr pWin;
1371706f2543Smrg    int rc;
1372706f2543Smrg
1373706f2543Smrg    /* For DRIDrawablePrivResType, the XID is the client's fake ID. The
1374706f2543Smrg     * important XID is the value in pResource. */
1375706f2543Smrg    id = (XID)(intptr_t)pResource;
1376706f2543Smrg    rc = dixLookupWindow(&pWin, id, serverClient, DixGetAttrAccess);
1377706f2543Smrg
1378706f2543Smrg    if (rc == Success) {
1379706f2543Smrg	DRIDrawablePrivPtr pDRIDrwPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
1380706f2543Smrg
1381706f2543Smrg	if (!pDRIDrwPriv)
1382706f2543Smrg	    return FALSE;
1383706f2543Smrg
1384706f2543Smrg	if (--pDRIDrwPriv->refCount == 0)
1385706f2543Smrg	    DRIDrawablePrivDestroy(pWin);
1386706f2543Smrg
1387706f2543Smrg	return TRUE;
1388706f2543Smrg    }
1389706f2543Smrg    else { /* pixmap (or for GLX 1.3, a PBuffer) */
1390706f2543Smrg	/* NOT_DONE */
1391706f2543Smrg	return FALSE;
1392706f2543Smrg    }
1393706f2543Smrg}
1394706f2543Smrg
1395706f2543SmrgBool
1396706f2543SmrgDRIGetDrawableInfo(ScreenPtr pScreen,
1397706f2543Smrg                   DrawablePtr pDrawable,
1398706f2543Smrg                   unsigned int* index,
1399706f2543Smrg                   unsigned int* stamp,
1400706f2543Smrg                   int* X,
1401706f2543Smrg                   int* Y,
1402706f2543Smrg                   int* W,
1403706f2543Smrg                   int* H,
1404706f2543Smrg                   int* numClipRects,
1405706f2543Smrg                   drm_clip_rect_t ** pClipRects,
1406706f2543Smrg                   int* backX,
1407706f2543Smrg                   int* backY,
1408706f2543Smrg                   int* numBackClipRects,
1409706f2543Smrg                   drm_clip_rect_t ** pBackClipRects)
1410706f2543Smrg{
1411706f2543Smrg    DRIScreenPrivPtr    pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1412706f2543Smrg    DRIDrawablePrivPtr	pDRIDrawablePriv, pOldDrawPriv;
1413706f2543Smrg    WindowPtr		pWin, pOldWin;
1414706f2543Smrg    int			i;
1415706f2543Smrg
1416706f2543Smrg#if 0
1417706f2543Smrg    printf("maxDrawableTableEntry = %d\n", pDRIPriv->pDriverInfo->maxDrawableTableEntry);
1418706f2543Smrg#endif
1419706f2543Smrg
1420706f2543Smrg    if (pDrawable->type == DRAWABLE_WINDOW) {
1421706f2543Smrg	pWin = (WindowPtr)pDrawable;
1422706f2543Smrg	if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
1423706f2543Smrg
1424706f2543Smrg	    /* Manage drawable table */
1425706f2543Smrg	    if (pDRIDrawablePriv->drawableIndex == -1) { /* load SAREA table */
1426706f2543Smrg
1427706f2543Smrg		/* Search table for empty entry */
1428706f2543Smrg		i = 0;
1429706f2543Smrg		while (i < pDRIPriv->pDriverInfo->maxDrawableTableEntry) {
1430706f2543Smrg		    if (!(pDRIPriv->DRIDrawables[i])) {
1431706f2543Smrg			pDRIPriv->DRIDrawables[i] = pDrawable;
1432706f2543Smrg			pDRIDrawablePriv->drawableIndex = i;
1433706f2543Smrg			pDRIPriv->pSAREA->drawableTable[i].stamp =
1434706f2543Smrg					    DRIDrawableValidationStamp++;
1435706f2543Smrg			break;
1436706f2543Smrg		    }
1437706f2543Smrg		    i++;
1438706f2543Smrg		}
1439706f2543Smrg
1440706f2543Smrg		/* Search table for oldest entry */
1441706f2543Smrg		if (i == pDRIPriv->pDriverInfo->maxDrawableTableEntry) {
1442706f2543Smrg                    unsigned int oldestStamp = ~0;
1443706f2543Smrg                    int oldestIndex = 0;
1444706f2543Smrg		    i = pDRIPriv->pDriverInfo->maxDrawableTableEntry;
1445706f2543Smrg		    while (i--) {
1446706f2543Smrg			if (pDRIPriv->pSAREA->drawableTable[i].stamp <
1447706f2543Smrg								oldestStamp) {
1448706f2543Smrg			    oldestIndex = i;
1449706f2543Smrg			    oldestStamp =
1450706f2543Smrg				pDRIPriv->pSAREA->drawableTable[i].stamp;
1451706f2543Smrg			}
1452706f2543Smrg		    }
1453706f2543Smrg		    pDRIDrawablePriv->drawableIndex = oldestIndex;
1454706f2543Smrg
1455706f2543Smrg		    /* release oldest drawable table entry */
1456706f2543Smrg		    pOldWin = (WindowPtr)pDRIPriv->DRIDrawables[oldestIndex];
1457706f2543Smrg		    pOldDrawPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pOldWin);
1458706f2543Smrg		    pOldDrawPriv->drawableIndex = -1;
1459706f2543Smrg
1460706f2543Smrg		    /* claim drawable table entry */
1461706f2543Smrg		    pDRIPriv->DRIDrawables[oldestIndex] = pDrawable;
1462706f2543Smrg
1463706f2543Smrg		    /* validate SAREA entry */
1464706f2543Smrg		    pDRIPriv->pSAREA->drawableTable[oldestIndex].stamp =
1465706f2543Smrg					DRIDrawableValidationStamp++;
1466706f2543Smrg
1467706f2543Smrg		    /* check for stamp wrap around */
1468706f2543Smrg		    if (oldestStamp > DRIDrawableValidationStamp) {
1469706f2543Smrg
1470706f2543Smrg			/* walk SAREA table and invalidate all drawables */
1471706f2543Smrg			for( i=0;
1472706f2543Smrg                             i < pDRIPriv->pDriverInfo->maxDrawableTableEntry;
1473706f2543Smrg                             i++) {
1474706f2543Smrg				pDRIPriv->pSAREA->drawableTable[i].stamp =
1475706f2543Smrg					DRIDrawableValidationStamp++;
1476706f2543Smrg			}
1477706f2543Smrg		    }
1478706f2543Smrg		}
1479706f2543Smrg
1480706f2543Smrg		/* If the driver wants to be notified when the index is
1481706f2543Smrg		 * set for a drawable, let it know now.
1482706f2543Smrg		 */
1483706f2543Smrg		if (pDRIPriv->pDriverInfo->SetDrawableIndex)
1484706f2543Smrg			pDRIPriv->pDriverInfo->SetDrawableIndex(pWin,
1485706f2543Smrg				pDRIDrawablePriv->drawableIndex);
1486706f2543Smrg
1487706f2543Smrg		/* reinit drawable ID if window is visible */
1488706f2543Smrg		if ((pWin->viewable) &&
1489706f2543Smrg		    (pDRIPriv->pDriverInfo->bufferRequests != DRI_NO_WINDOWS))
1490706f2543Smrg		{
1491706f2543Smrg		    (*pDRIPriv->pDriverInfo->InitBuffers)(pWin,
1492706f2543Smrg			    &pWin->clipList, pDRIDrawablePriv->drawableIndex);
1493706f2543Smrg		}
1494706f2543Smrg	    }
1495706f2543Smrg
1496706f2543Smrg	    *index = pDRIDrawablePriv->drawableIndex;
1497706f2543Smrg	    *stamp = pDRIPriv->pSAREA->drawableTable[*index].stamp;
1498706f2543Smrg	    *X = (int)(pWin->drawable.x);
1499706f2543Smrg	    *Y = (int)(pWin->drawable.y);
1500706f2543Smrg#if 0
1501706f2543Smrg	    *W = (int)(pWin->winSize.extents.x2 - pWin->winSize.extents.x1);
1502706f2543Smrg	    *H = (int)(pWin->winSize.extents.y2 - pWin->winSize.extents.y1);
1503706f2543Smrg#endif
1504706f2543Smrg	    *W = (int)(pWin->drawable.width);
1505706f2543Smrg	    *H = (int)(pWin->drawable.height);
1506706f2543Smrg	    *numClipRects = RegionNumRects(&pWin->clipList);
1507706f2543Smrg	    *pClipRects = (drm_clip_rect_t *)RegionRects(&pWin->clipList);
1508706f2543Smrg
1509706f2543Smrg	    if (!*numClipRects && pDRIPriv->fullscreen) {
1510706f2543Smrg				/* use fake full-screen clip rect */
1511706f2543Smrg		pDRIPriv->fullscreen_rect.x1 = *X;
1512706f2543Smrg		pDRIPriv->fullscreen_rect.y1 = *Y;
1513706f2543Smrg		pDRIPriv->fullscreen_rect.x2 = *X + *W;
1514706f2543Smrg		pDRIPriv->fullscreen_rect.y2 = *Y + *H;
1515706f2543Smrg
1516706f2543Smrg		*numClipRects = 1;
1517706f2543Smrg		*pClipRects   = &pDRIPriv->fullscreen_rect;
1518706f2543Smrg	    }
1519706f2543Smrg
1520706f2543Smrg	    *backX = *X;
1521706f2543Smrg	    *backY = *Y;
1522706f2543Smrg
1523706f2543Smrg	    if (pDRIPriv->nrWindowsVisible == 1 && *numClipRects) {
1524706f2543Smrg	       /* Use a single cliprect. */
1525706f2543Smrg
1526706f2543Smrg	       int x0 = *X;
1527706f2543Smrg	       int y0 = *Y;
1528706f2543Smrg	       int x1 = x0 + *W;
1529706f2543Smrg	       int y1 = y0 + *H;
1530706f2543Smrg
1531706f2543Smrg	       if (x0 < 0) x0 = 0;
1532706f2543Smrg	       if (y0 < 0) y0 = 0;
1533706f2543Smrg	       if (x1 > pScreen->width) x1 = pScreen->width;
1534706f2543Smrg	       if (y1 > pScreen->height) y1 = pScreen->height;
1535706f2543Smrg
1536706f2543Smrg	       if (y0 >= y1 || x0 >= x1) {
1537706f2543Smrg		    *numBackClipRects = 0;
1538706f2543Smrg		    *pBackClipRects = NULL;
1539706f2543Smrg	       } else {
1540706f2543Smrg		    pDRIPriv->private_buffer_rect.x1 = x0;
1541706f2543Smrg		    pDRIPriv->private_buffer_rect.y1 = y0;
1542706f2543Smrg		    pDRIPriv->private_buffer_rect.x2 = x1;
1543706f2543Smrg		    pDRIPriv->private_buffer_rect.y2 = y1;
1544706f2543Smrg
1545706f2543Smrg		    *numBackClipRects = 1;
1546706f2543Smrg		    *pBackClipRects = &(pDRIPriv->private_buffer_rect);
1547706f2543Smrg	       }
1548706f2543Smrg	    } else {
1549706f2543Smrg	       /* Use the frontbuffer cliprects for back buffers.  */
1550706f2543Smrg	       *numBackClipRects = 0;
1551706f2543Smrg	       *pBackClipRects = 0;
1552706f2543Smrg	    }
1553706f2543Smrg	}
1554706f2543Smrg	else {
1555706f2543Smrg	    /* Not a DRIDrawable */
1556706f2543Smrg	    return FALSE;
1557706f2543Smrg	}
1558706f2543Smrg    }
1559706f2543Smrg    else { /* pixmap (or for GLX 1.3, a PBuffer) */
1560706f2543Smrg	/* NOT_DONE */
1561706f2543Smrg	return FALSE;
1562706f2543Smrg    }
1563706f2543Smrg
1564706f2543Smrg    return TRUE;
1565706f2543Smrg}
1566706f2543Smrg
1567706f2543SmrgBool
1568706f2543SmrgDRIGetDeviceInfo(ScreenPtr pScreen,
1569706f2543Smrg                 drm_handle_t * hFrameBuffer,
1570706f2543Smrg                 int* fbOrigin,
1571706f2543Smrg                 int* fbSize,
1572706f2543Smrg                 int* fbStride,
1573706f2543Smrg                 int* devPrivateSize,
1574706f2543Smrg                 void** pDevPrivate)
1575706f2543Smrg{
1576706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1577706f2543Smrg
1578706f2543Smrg    *hFrameBuffer = pDRIPriv->pDriverInfo->hFrameBuffer;
1579706f2543Smrg    *fbOrigin = 0;
1580706f2543Smrg    *fbSize = pDRIPriv->pDriverInfo->frameBufferSize;
1581706f2543Smrg    *fbStride = pDRIPriv->pDriverInfo->frameBufferStride;
1582706f2543Smrg    *devPrivateSize = pDRIPriv->pDriverInfo->devPrivateSize;
1583706f2543Smrg    *pDevPrivate = pDRIPriv->pDriverInfo->devPrivate;
1584706f2543Smrg
1585706f2543Smrg    return TRUE;
1586706f2543Smrg}
1587706f2543Smrg
1588706f2543SmrgDRIInfoPtr
1589706f2543SmrgDRICreateInfoRec(void)
1590706f2543Smrg{
1591706f2543Smrg    DRIInfoPtr inforec = (DRIInfoPtr)calloc(1, sizeof(DRIInfoRec));
1592706f2543Smrg    if (!inforec) return NULL;
1593706f2543Smrg
1594706f2543Smrg    /* Initialize defaults */
1595706f2543Smrg    inforec->busIdString = NULL;
1596706f2543Smrg
1597706f2543Smrg    /* Wrapped function defaults */
1598706f2543Smrg    inforec->wrap.WakeupHandler         = DRIDoWakeupHandler;
1599706f2543Smrg    inforec->wrap.BlockHandler          = DRIDoBlockHandler;
1600706f2543Smrg    inforec->wrap.WindowExposures       = DRIWindowExposures;
1601706f2543Smrg    inforec->wrap.CopyWindow            = DRICopyWindow;
1602706f2543Smrg    inforec->wrap.ValidateTree          = DRIValidateTree;
1603706f2543Smrg    inforec->wrap.PostValidateTree      = DRIPostValidateTree;
1604706f2543Smrg    inforec->wrap.ClipNotify            = DRIClipNotify;
1605706f2543Smrg    inforec->wrap.AdjustFrame           = DRIAdjustFrame;
1606706f2543Smrg
1607706f2543Smrg    inforec->TransitionTo2d = 0;
1608706f2543Smrg    inforec->TransitionTo3d = 0;
1609706f2543Smrg    inforec->SetDrawableIndex = 0;
1610706f2543Smrg
1611706f2543Smrg    return inforec;
1612706f2543Smrg}
1613706f2543Smrg
1614706f2543Smrgvoid
1615706f2543SmrgDRIDestroyInfoRec(DRIInfoPtr DRIInfo)
1616706f2543Smrg{
1617706f2543Smrg    free(DRIInfo->busIdString);
1618706f2543Smrg    free((char*)DRIInfo);
1619706f2543Smrg}
1620706f2543Smrg
1621706f2543Smrg
1622706f2543Smrgvoid
1623706f2543SmrgDRIWakeupHandler(pointer wakeupData, int result, pointer pReadmask)
1624706f2543Smrg{
1625706f2543Smrg    int i;
1626706f2543Smrg
1627706f2543Smrg    for (i = 0; i < screenInfo.numScreens; i++) {
1628706f2543Smrg	ScreenPtr        pScreen  = screenInfo.screens[i];
1629706f2543Smrg	DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1630706f2543Smrg
1631706f2543Smrg	if (pDRIPriv &&
1632706f2543Smrg	    pDRIPriv->pDriverInfo->wrap.WakeupHandler)
1633706f2543Smrg	    (*pDRIPriv->pDriverInfo->wrap.WakeupHandler)(i, wakeupData,
1634706f2543Smrg							 result, pReadmask);
1635706f2543Smrg    }
1636706f2543Smrg}
1637706f2543Smrg
1638706f2543Smrgvoid
1639706f2543SmrgDRIBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask)
1640706f2543Smrg{
1641706f2543Smrg    int i;
1642706f2543Smrg
1643706f2543Smrg    for (i = 0; i < screenInfo.numScreens; i++) {
1644706f2543Smrg	ScreenPtr        pScreen  = screenInfo.screens[i];
1645706f2543Smrg	DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1646706f2543Smrg
1647706f2543Smrg	if (pDRIPriv &&
1648706f2543Smrg	    pDRIPriv->pDriverInfo->wrap.BlockHandler)
1649706f2543Smrg	    (*pDRIPriv->pDriverInfo->wrap.BlockHandler)(i, blockData,
1650706f2543Smrg							pTimeout, pReadmask);
1651706f2543Smrg    }
1652706f2543Smrg}
1653706f2543Smrg
1654706f2543Smrgvoid
1655706f2543SmrgDRIDoWakeupHandler(int screenNum, pointer wakeupData,
1656706f2543Smrg                   unsigned long result, pointer pReadmask)
1657706f2543Smrg{
1658706f2543Smrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
1659706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1660706f2543Smrg
1661706f2543Smrg    DRILock(pScreen, 0);
1662706f2543Smrg    if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
1663706f2543Smrg	/* hide X context by swapping 2D component here */
1664706f2543Smrg	(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
1665706f2543Smrg					      DRI_3D_SYNC,
1666706f2543Smrg					      DRI_2D_CONTEXT,
1667706f2543Smrg					      pDRIPriv->partial3DContextStore,
1668706f2543Smrg					      DRI_2D_CONTEXT,
1669706f2543Smrg					      pDRIPriv->hiddenContextStore);
1670706f2543Smrg    }
1671706f2543Smrg}
1672706f2543Smrg
1673706f2543Smrgvoid
1674706f2543SmrgDRIDoBlockHandler(int screenNum, pointer blockData,
1675706f2543Smrg                  pointer pTimeout, pointer pReadmask)
1676706f2543Smrg{
1677706f2543Smrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
1678706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1679706f2543Smrg
1680706f2543Smrg    if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
1681706f2543Smrg	/* hide X context by swapping 2D component here */
1682706f2543Smrg	(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
1683706f2543Smrg					      DRI_2D_SYNC,
1684706f2543Smrg					      DRI_NO_CONTEXT,
1685706f2543Smrg					      NULL,
1686706f2543Smrg					      DRI_2D_CONTEXT,
1687706f2543Smrg					      pDRIPriv->partial3DContextStore);
1688706f2543Smrg    }
1689706f2543Smrg
1690706f2543Smrg    if (pDRIPriv->windowsTouched)
1691706f2543Smrg        DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1);
1692706f2543Smrg    pDRIPriv->windowsTouched = FALSE;
1693706f2543Smrg
1694706f2543Smrg    DRIUnlock(pScreen);
1695706f2543Smrg}
1696706f2543Smrg
1697706f2543Smrgvoid
1698706f2543SmrgDRISwapContext(int drmFD, void *oldctx, void *newctx)
1699706f2543Smrg{
1700706f2543Smrg    DRIContextPrivPtr oldContext      = (DRIContextPrivPtr)oldctx;
1701706f2543Smrg    DRIContextPrivPtr newContext      = (DRIContextPrivPtr)newctx;
1702706f2543Smrg    ScreenPtr         pScreen         = newContext->pScreen;
1703706f2543Smrg    DRIScreenPrivPtr  pDRIPriv        = DRI_SCREEN_PRIV(pScreen);
1704706f2543Smrg    void*             oldContextStore = NULL;
1705706f2543Smrg    DRIContextType    oldContextType;
1706706f2543Smrg    void*             newContextStore = NULL;
1707706f2543Smrg    DRIContextType    newContextType;
1708706f2543Smrg    DRISyncType       syncType;
1709706f2543Smrg#ifdef DEBUG
1710706f2543Smrg    static int        count = 0;
1711706f2543Smrg
1712706f2543Smrg    if (!newContext) {
1713706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_ERROR,
1714706f2543Smrg		  "[DRI] Context Switch Error: oldContext=%x, newContext=%x\n",
1715706f2543Smrg		  oldContext, newContext);
1716706f2543Smrg	return;
1717706f2543Smrg    }
1718706f2543Smrg
1719706f2543Smrg    /* usefull for debugging, just print out after n context switches */
1720706f2543Smrg    if (!count || !(count % 1)) {
1721706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_INFO,
1722706f2543Smrg		  "[DRI] Context switch %5d from %p/0x%08x (%d)\n",
1723706f2543Smrg		  count,
1724706f2543Smrg		  oldContext,
1725706f2543Smrg		  oldContext ? oldContext->flags : 0,
1726706f2543Smrg		  oldContext ? oldContext->hwContext : -1);
1727706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_INFO,
1728706f2543Smrg		  "[DRI] Context switch %5d to   %p/0x%08x (%d)\n",
1729706f2543Smrg		  count,
1730706f2543Smrg		  newContext,
1731706f2543Smrg		  newContext ? newContext->flags : 0,
1732706f2543Smrg		  newContext ? newContext->hwContext : -1);
1733706f2543Smrg    }
1734706f2543Smrg    ++count;
1735706f2543Smrg#endif
1736706f2543Smrg
1737706f2543Smrg    if (!pDRIPriv->pDriverInfo->SwapContext) {
1738706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_ERROR,
1739706f2543Smrg		  "[DRI] DDX driver missing context swap call back\n");
1740706f2543Smrg	return;
1741706f2543Smrg    }
1742706f2543Smrg
1743706f2543Smrg    if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
1744706f2543Smrg
1745706f2543Smrg        /* only 3D contexts are swapped in this case */
1746706f2543Smrg	if (oldContext) {
1747706f2543Smrg	    oldContextStore     = DRIGetContextStore(oldContext);
1748706f2543Smrg	    oldContext->valid3D = TRUE;
1749706f2543Smrg	    oldContextType      = DRI_3D_CONTEXT;
1750706f2543Smrg	} else {
1751706f2543Smrg	    oldContextType      = DRI_NO_CONTEXT;
1752706f2543Smrg	}
1753706f2543Smrg	newContextStore = DRIGetContextStore(newContext);
1754706f2543Smrg	if ((newContext->valid3D) &&
1755706f2543Smrg	  (newContext->hwContext != pDRIPriv->myContext)) {
1756706f2543Smrg	    newContextType = DRI_3D_CONTEXT;
1757706f2543Smrg	}
1758706f2543Smrg	else {
1759706f2543Smrg	    newContextType = DRI_2D_CONTEXT;
1760706f2543Smrg	}
1761706f2543Smrg	syncType = DRI_3D_SYNC;
1762706f2543Smrg    }
1763706f2543Smrg    else /* default: driverSwapMethod == DRI_SERVER_SWAP */ {
1764706f2543Smrg
1765706f2543Smrg        /* optimize 2D context swaps */
1766706f2543Smrg
1767706f2543Smrg	if (newContext->flags & DRI_CONTEXT_2DONLY) {
1768706f2543Smrg	    /* go from 3D context to 2D context and only save 2D
1769706f2543Smrg             * subset of 3D state
1770706f2543Smrg             */
1771706f2543Smrg	    oldContextStore = DRIGetContextStore(oldContext);
1772706f2543Smrg	    oldContextType = DRI_2D_CONTEXT;
1773706f2543Smrg	    newContextStore = DRIGetContextStore(newContext);
1774706f2543Smrg	    newContextType = DRI_2D_CONTEXT;
1775706f2543Smrg	    syncType = DRI_3D_SYNC;
1776706f2543Smrg	    pDRIPriv->lastPartial3DContext = oldContext;
1777706f2543Smrg	}
1778706f2543Smrg	else if (oldContext->flags & DRI_CONTEXT_2DONLY) {
1779706f2543Smrg	    if (pDRIPriv->lastPartial3DContext == newContext) {
1780706f2543Smrg		/* go from 2D context back to previous 3D context and
1781706f2543Smrg		 * only restore 2D subset of previous 3D state
1782706f2543Smrg		 */
1783706f2543Smrg		oldContextStore = DRIGetContextStore(oldContext);
1784706f2543Smrg		oldContextType = DRI_2D_CONTEXT;
1785706f2543Smrg		newContextStore = DRIGetContextStore(newContext);
1786706f2543Smrg		newContextType = DRI_2D_CONTEXT;
1787706f2543Smrg		syncType = DRI_2D_SYNC;
1788706f2543Smrg	    }
1789706f2543Smrg	    else {
1790706f2543Smrg		/* go from 2D context to a different 3D context */
1791706f2543Smrg
1792706f2543Smrg		/* call DDX driver to do partial restore */
1793706f2543Smrg		oldContextStore = DRIGetContextStore(oldContext);
1794706f2543Smrg		newContextStore =
1795706f2543Smrg			DRIGetContextStore(pDRIPriv->lastPartial3DContext);
1796706f2543Smrg		(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
1797706f2543Smrg						      DRI_2D_SYNC,
1798706f2543Smrg						      DRI_2D_CONTEXT,
1799706f2543Smrg						      oldContextStore,
1800706f2543Smrg						      DRI_2D_CONTEXT,
1801706f2543Smrg						      newContextStore);
1802706f2543Smrg
1803706f2543Smrg		/* now setup for a complete 3D swap */
1804706f2543Smrg		oldContextStore = newContextStore;
1805706f2543Smrg		oldContext->valid3D = TRUE;
1806706f2543Smrg		oldContextType = DRI_3D_CONTEXT;
1807706f2543Smrg		newContextStore = DRIGetContextStore(newContext);
1808706f2543Smrg		if ((newContext->valid3D) &&
1809706f2543Smrg		  (newContext->hwContext != pDRIPriv->myContext)) {
1810706f2543Smrg		    newContextType = DRI_3D_CONTEXT;
1811706f2543Smrg		}
1812706f2543Smrg		else {
1813706f2543Smrg		    newContextType = DRI_2D_CONTEXT;
1814706f2543Smrg		}
1815706f2543Smrg		syncType = DRI_NO_SYNC;
1816706f2543Smrg	    }
1817706f2543Smrg	}
1818706f2543Smrg	else {
1819706f2543Smrg	    /* now setup for a complete 3D swap */
1820706f2543Smrg	    oldContextStore = newContextStore;
1821706f2543Smrg	    oldContext->valid3D = TRUE;
1822706f2543Smrg	    oldContextType = DRI_3D_CONTEXT;
1823706f2543Smrg	    newContextStore = DRIGetContextStore(newContext);
1824706f2543Smrg	    if ((newContext->valid3D) &&
1825706f2543Smrg	      (newContext->hwContext != pDRIPriv->myContext)) {
1826706f2543Smrg		newContextType = DRI_3D_CONTEXT;
1827706f2543Smrg	    }
1828706f2543Smrg	    else {
1829706f2543Smrg		newContextType = DRI_2D_CONTEXT;
1830706f2543Smrg	    }
1831706f2543Smrg	    syncType = DRI_3D_SYNC;
1832706f2543Smrg	}
1833706f2543Smrg    }
1834706f2543Smrg
1835706f2543Smrg    /* call DDX driver to perform the swap */
1836706f2543Smrg    (*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
1837706f2543Smrg					  syncType,
1838706f2543Smrg					  oldContextType,
1839706f2543Smrg					  oldContextStore,
1840706f2543Smrg					  newContextType,
1841706f2543Smrg					  newContextStore);
1842706f2543Smrg}
1843706f2543Smrg
1844706f2543Smrgvoid*
1845706f2543SmrgDRIGetContextStore(DRIContextPrivPtr context)
1846706f2543Smrg{
1847706f2543Smrg    return((void *)context->pContextStore);
1848706f2543Smrg}
1849706f2543Smrg
1850706f2543Smrgvoid
1851706f2543SmrgDRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg)
1852706f2543Smrg{
1853706f2543Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
1854706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1855706f2543Smrg    DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
1856706f2543Smrg
1857706f2543Smrg    if(pDRIDrawablePriv) {
1858706f2543Smrg         (*pDRIPriv->pDriverInfo->InitBuffers)(pWin, prgn,
1859706f2543Smrg                                               pDRIDrawablePriv->drawableIndex);
1860706f2543Smrg    }
1861706f2543Smrg
1862706f2543Smrg    /* call lower wrapped functions */
1863706f2543Smrg    if (pDRIPriv && pDRIPriv->wrap.WindowExposures) {
1864706f2543Smrg
1865706f2543Smrg	/* unwrap */
1866706f2543Smrg	pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
1867706f2543Smrg
1868706f2543Smrg	/* call lower layers */
1869706f2543Smrg	(*pScreen->WindowExposures)(pWin, prgn, bsreg);
1870706f2543Smrg
1871706f2543Smrg	/* rewrap */
1872706f2543Smrg	pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
1873706f2543Smrg	pScreen->WindowExposures = DRIWindowExposures;
1874706f2543Smrg    }
1875706f2543Smrg}
1876706f2543Smrg
1877706f2543Smrg
1878706f2543Smrgstatic int
1879706f2543SmrgDRITreeTraversal(WindowPtr pWin, pointer data)
1880706f2543Smrg{
1881706f2543Smrg    DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
1882706f2543Smrg
1883706f2543Smrg    if(pDRIDrawablePriv) {
1884706f2543Smrg        ScreenPtr pScreen = pWin->drawable.pScreen;
1885706f2543Smrg        DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1886706f2543Smrg
1887706f2543Smrg	if(RegionNumRects(&(pWin->clipList)) > 0) {
1888706f2543Smrg	   RegionPtr reg = (RegionPtr)data;
1889706f2543Smrg
1890706f2543Smrg	   RegionUnion(reg, reg, &(pWin->clipList));
1891706f2543Smrg	   pDRIPriv->nrWalked++;
1892706f2543Smrg	}
1893706f2543Smrg
1894706f2543Smrg	if(pDRIPriv->nrWindows == pDRIPriv->nrWalked)
1895706f2543Smrg	   return WT_STOPWALKING;
1896706f2543Smrg    }
1897706f2543Smrg    return WT_WALKCHILDREN;
1898706f2543Smrg}
1899706f2543Smrg
1900706f2543SmrgBool
1901706f2543SmrgDRIDestroyWindow(WindowPtr pWin)
1902706f2543Smrg{
1903706f2543Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
1904706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1905706f2543Smrg    Bool retval = TRUE;
1906706f2543Smrg
1907706f2543Smrg    DRIDrawablePrivDestroy(pWin);
1908706f2543Smrg
1909706f2543Smrg    /* call lower wrapped functions */
1910706f2543Smrg    if(pDRIPriv->DestroyWindow) {
1911706f2543Smrg	/* unwrap */
1912706f2543Smrg	pScreen->DestroyWindow = pDRIPriv->DestroyWindow;
1913706f2543Smrg
1914706f2543Smrg	/* call lower layers */
1915706f2543Smrg	retval = (*pScreen->DestroyWindow)(pWin);
1916706f2543Smrg
1917706f2543Smrg	/* rewrap */
1918706f2543Smrg	pDRIPriv->DestroyWindow = pScreen->DestroyWindow;
1919706f2543Smrg	pScreen->DestroyWindow = DRIDestroyWindow;
1920706f2543Smrg    }
1921706f2543Smrg
1922706f2543Smrg    return retval;
1923706f2543Smrg}
1924706f2543Smrg
1925706f2543Smrgvoid
1926706f2543SmrgDRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
1927706f2543Smrg{
1928706f2543Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
1929706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
1930706f2543Smrg
1931706f2543Smrg    if(!pDRIPriv) return;
1932706f2543Smrg
1933706f2543Smrg    if(pDRIPriv->nrWindowsVisible > 0) {
1934706f2543Smrg       RegionRec reg;
1935706f2543Smrg
1936706f2543Smrg       RegionNull(&reg);
1937706f2543Smrg       pDRIPriv->nrWalked = 0;
1938706f2543Smrg       TraverseTree(pWin, DRITreeTraversal, (pointer)(&reg));
1939706f2543Smrg
1940706f2543Smrg       if(RegionNotEmpty(&reg)) {
1941706f2543Smrg           RegionTranslate(&reg, ptOldOrg.x - pWin->drawable.x,
1942706f2543Smrg                                        ptOldOrg.y - pWin->drawable.y);
1943706f2543Smrg           RegionIntersect(&reg, &reg, prgnSrc);
1944706f2543Smrg
1945706f2543Smrg           /* The MoveBuffers interface is not ideal */
1946706f2543Smrg           (*pDRIPriv->pDriverInfo->MoveBuffers)(pWin, ptOldOrg, &reg,
1947706f2543Smrg				pDRIPriv->pDriverInfo->ddxDrawableTableEntry);
1948706f2543Smrg       }
1949706f2543Smrg
1950706f2543Smrg       RegionUninit(&reg);
1951706f2543Smrg    }
1952706f2543Smrg
1953706f2543Smrg    /* call lower wrapped functions */
1954706f2543Smrg    if(pDRIPriv->wrap.CopyWindow) {
1955706f2543Smrg	/* unwrap */
1956706f2543Smrg	pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
1957706f2543Smrg
1958706f2543Smrg	/* call lower layers */
1959706f2543Smrg	(*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
1960706f2543Smrg
1961706f2543Smrg	/* rewrap */
1962706f2543Smrg	pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
1963706f2543Smrg	pScreen->CopyWindow = DRICopyWindow;
1964706f2543Smrg    }
1965706f2543Smrg}
1966706f2543Smrg
1967706f2543Smrgstatic void
1968706f2543SmrgDRIGetSecs(long *secs, long *usecs)
1969706f2543Smrg{
1970706f2543Smrg    struct timeval tv;
1971706f2543Smrg
1972706f2543Smrg    gettimeofday(&tv, NULL);
1973706f2543Smrg
1974706f2543Smrg    *secs  = tv.tv_sec;
1975706f2543Smrg    *usecs = tv.tv_usec;
1976706f2543Smrg}
1977706f2543Smrg
1978706f2543Smrgstatic unsigned long
1979706f2543SmrgDRIComputeMilliSeconds(unsigned long s_secs, unsigned long s_usecs,
1980706f2543Smrg		       unsigned long f_secs, unsigned long f_usecs)
1981706f2543Smrg{
1982706f2543Smrg    if (f_usecs < s_usecs) {
1983706f2543Smrg	--f_secs;
1984706f2543Smrg	f_usecs += 1000000;
1985706f2543Smrg    }
1986706f2543Smrg    return (f_secs - s_secs) * 1000 + (f_usecs - s_usecs) / 1000;
1987706f2543Smrg}
1988706f2543Smrg
1989706f2543Smrgstatic void
1990706f2543SmrgDRISpinLockTimeout(drmLock *lock, int val, unsigned long timeout /* in mS */)
1991706f2543Smrg{
1992706f2543Smrg    int  count = 10000;
1993706f2543Smrg#if !defined(__alpha__) && !defined(__powerpc__)
1994706f2543Smrg    char ret;
1995706f2543Smrg#else
1996706f2543Smrg    int ret;
1997706f2543Smrg#endif
1998706f2543Smrg    long s_secs, s_usecs;
1999706f2543Smrg    long f_secs, f_usecs;
2000706f2543Smrg    long msecs;
2001706f2543Smrg    long prev  = 0;
2002706f2543Smrg
2003706f2543Smrg    DRIGetSecs(&s_secs, &s_usecs);
2004706f2543Smrg
2005706f2543Smrg    do {
2006706f2543Smrg	DRM_SPINLOCK_COUNT(lock, val, count, ret);
2007706f2543Smrg	if (!ret) return;	/* Got lock */
2008706f2543Smrg	DRIGetSecs(&f_secs, &f_usecs);
2009706f2543Smrg	msecs = DRIComputeMilliSeconds(s_secs, s_usecs, f_secs, f_usecs);
2010706f2543Smrg	if (msecs - prev < 250) count *= 2; /* Not more than 0.5S */
2011706f2543Smrg    } while (msecs < timeout);
2012706f2543Smrg
2013706f2543Smrg				/* Didn't get lock, so take it.  The worst
2014706f2543Smrg                                   that can happen is that there is some
2015706f2543Smrg                                   garbage written to the wrong part of the
2016706f2543Smrg                                   framebuffer that a refresh will repair.
2017706f2543Smrg                                   That's undesirable, but better than
2018706f2543Smrg                                   locking the server.  This should be a
2019706f2543Smrg                                   very rare event. */
2020706f2543Smrg    DRM_SPINLOCK_TAKE(lock, val);
2021706f2543Smrg}
2022706f2543Smrg
2023706f2543Smrgstatic void
2024706f2543SmrgDRILockTree(ScreenPtr pScreen)
2025706f2543Smrg{
2026706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2027706f2543Smrg
2028706f2543Smrg    if(!pDRIPriv) return;
2029706f2543Smrg
2030706f2543Smrg    /* Restore the last known 3D context if the X context is hidden */
2031706f2543Smrg    if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
2032706f2543Smrg	(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
2033706f2543Smrg					      DRI_2D_SYNC,
2034706f2543Smrg					      DRI_NO_CONTEXT,
2035706f2543Smrg					      NULL,
2036706f2543Smrg					      DRI_2D_CONTEXT,
2037706f2543Smrg					      pDRIPriv->partial3DContextStore);
2038706f2543Smrg    }
2039706f2543Smrg
2040706f2543Smrg    /* Call kernel to release lock */
2041706f2543Smrg    DRIUnlock(pScreen);
2042706f2543Smrg
2043706f2543Smrg    /* Grab drawable spin lock: a time out between 10 and 30 seconds is
2044706f2543Smrg       appropriate, since this should never time out except in the case of
2045706f2543Smrg       client death while the lock is being held.  The timeout must be
2046706f2543Smrg       greater than any reasonable rendering time. */
2047706f2543Smrg    DRISpinLockTimeout(&pDRIPriv->pSAREA->drawable_lock, 1, 10000); /*10 secs*/
2048706f2543Smrg
2049706f2543Smrg    /* Call kernel flush outstanding buffers and relock */
2050706f2543Smrg    DRILock(pScreen, DRM_LOCK_QUIESCENT|DRM_LOCK_FLUSH_ALL);
2051706f2543Smrg
2052706f2543Smrg    /* Switch back to our 2D context if the X context is hidden */
2053706f2543Smrg    if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) {
2054706f2543Smrg	/* hide X context by swapping 2D component here */
2055706f2543Smrg	(*pDRIPriv->pDriverInfo->SwapContext)(pScreen,
2056706f2543Smrg					      DRI_3D_SYNC,
2057706f2543Smrg					      DRI_2D_CONTEXT,
2058706f2543Smrg					      pDRIPriv->partial3DContextStore,
2059706f2543Smrg					      DRI_2D_CONTEXT,
2060706f2543Smrg					      pDRIPriv->hiddenContextStore);
2061706f2543Smrg    }
2062706f2543Smrg}
2063706f2543Smrg
2064706f2543Smrgint
2065706f2543SmrgDRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
2066706f2543Smrg{
2067706f2543Smrg    ScreenPtr pScreen = pParent->drawable.pScreen;
2068706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2069706f2543Smrg
2070706f2543Smrg    int returnValue = 1; /* always return 1, not checked by dix/window.c */
2071706f2543Smrg
2072706f2543Smrg    if(!pDRIPriv) return returnValue;
2073706f2543Smrg
2074706f2543Smrg    /* call lower wrapped functions */
2075706f2543Smrg    if(pDRIPriv->wrap.ValidateTree) {
2076706f2543Smrg	/* unwrap */
2077706f2543Smrg	pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree;
2078706f2543Smrg
2079706f2543Smrg	/* call lower layers */
2080706f2543Smrg	returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind);
2081706f2543Smrg
2082706f2543Smrg	/* rewrap */
2083706f2543Smrg	pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
2084706f2543Smrg	pScreen->ValidateTree = DRIValidateTree;
2085706f2543Smrg    }
2086706f2543Smrg
2087706f2543Smrg    return returnValue;
2088706f2543Smrg}
2089706f2543Smrg
2090706f2543Smrgvoid
2091706f2543SmrgDRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
2092706f2543Smrg{
2093706f2543Smrg    ScreenPtr pScreen;
2094706f2543Smrg    DRIScreenPrivPtr pDRIPriv;
2095706f2543Smrg
2096706f2543Smrg    if (pParent) {
2097706f2543Smrg	pScreen = pParent->drawable.pScreen;
2098706f2543Smrg    } else {
2099706f2543Smrg	pScreen = pChild->drawable.pScreen;
2100706f2543Smrg    }
2101706f2543Smrg    if(!(pDRIPriv = DRI_SCREEN_PRIV(pScreen))) return;
2102706f2543Smrg
2103706f2543Smrg    if (pDRIPriv->wrap.PostValidateTree) {
2104706f2543Smrg	/* unwrap */
2105706f2543Smrg	pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree;
2106706f2543Smrg
2107706f2543Smrg	/* call lower layers */
2108706f2543Smrg	(*pScreen->PostValidateTree)(pParent, pChild, kind);
2109706f2543Smrg
2110706f2543Smrg	/* rewrap */
2111706f2543Smrg	pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
2112706f2543Smrg	pScreen->PostValidateTree = DRIPostValidateTree;
2113706f2543Smrg    }
2114706f2543Smrg}
2115706f2543Smrg
2116706f2543Smrgvoid
2117706f2543SmrgDRIClipNotify(WindowPtr pWin, int dx, int dy)
2118706f2543Smrg{
2119706f2543Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
2120706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2121706f2543Smrg    DRIDrawablePrivPtr	pDRIDrawablePriv;
2122706f2543Smrg
2123706f2543Smrg    if(!pDRIPriv) return;
2124706f2543Smrg
2125706f2543Smrg    if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
2126706f2543Smrg        int nrects = RegionNumRects(&pWin->clipList);
2127706f2543Smrg
2128706f2543Smrg        if(!pDRIPriv->windowsTouched) {
2129706f2543Smrg            DRILockTree(pScreen);
2130706f2543Smrg            pDRIPriv->windowsTouched = TRUE;
2131706f2543Smrg        }
2132706f2543Smrg
2133706f2543Smrg	if (nrects && !pDRIDrawablePriv->nrects)
2134706f2543Smrg	    DRIIncreaseNumberVisible(pScreen);
2135706f2543Smrg	else if (!nrects && pDRIDrawablePriv->nrects)
2136706f2543Smrg	    DRIDecreaseNumberVisible(pScreen);
2137706f2543Smrg	else
2138706f2543Smrg	    DRIDriverClipNotify(pScreen);
2139706f2543Smrg
2140706f2543Smrg	pDRIDrawablePriv->nrects = nrects;
2141706f2543Smrg
2142706f2543Smrg	pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp
2143706f2543Smrg	    = DRIDrawableValidationStamp++;
2144706f2543Smrg
2145706f2543Smrg	drmUpdateDrawableInfo(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable,
2146706f2543Smrg			      DRM_DRAWABLE_CLIPRECTS,
2147706f2543Smrg			      nrects, RegionRects(&pWin->clipList));
2148706f2543Smrg    }
2149706f2543Smrg
2150706f2543Smrg    /* call lower wrapped functions */
2151706f2543Smrg    if(pDRIPriv->wrap.ClipNotify) {
2152706f2543Smrg
2153706f2543Smrg	/* unwrap */
2154706f2543Smrg        pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
2155706f2543Smrg
2156706f2543Smrg	/* call lower layers */
2157706f2543Smrg        (*pScreen->ClipNotify)(pWin, dx, dy);
2158706f2543Smrg
2159706f2543Smrg	/* rewrap */
2160706f2543Smrg        pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
2161706f2543Smrg        pScreen->ClipNotify = DRIClipNotify;
2162706f2543Smrg    }
2163706f2543Smrg}
2164706f2543Smrg
2165706f2543SmrgCARD32
2166706f2543SmrgDRIGetDrawableIndex(WindowPtr pWin)
2167706f2543Smrg{
2168706f2543Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
2169706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2170706f2543Smrg    DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
2171706f2543Smrg    CARD32 index;
2172706f2543Smrg
2173706f2543Smrg    if (pDRIDrawablePriv) {
2174706f2543Smrg	index = pDRIDrawablePriv->drawableIndex;
2175706f2543Smrg    }
2176706f2543Smrg    else {
2177706f2543Smrg	index = pDRIPriv->pDriverInfo->ddxDrawableTableEntry;
2178706f2543Smrg    }
2179706f2543Smrg
2180706f2543Smrg    return index;
2181706f2543Smrg}
2182706f2543Smrg
2183706f2543Smrgunsigned int
2184706f2543SmrgDRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index)
2185706f2543Smrg{
2186706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2187706f2543Smrg    return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp;
2188706f2543Smrg}
2189706f2543Smrg
2190706f2543Smrg
2191706f2543Smrgvoid
2192706f2543SmrgDRIPrintDrawableLock(ScreenPtr pScreen, char *msg)
2193706f2543Smrg{
2194706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2195706f2543Smrg
2196706f2543Smrg    ErrorF("%s: %d\n", msg,  pDRIPriv->pSAREA->drawable_lock.lock);
2197706f2543Smrg}
2198706f2543Smrg
2199706f2543Smrgvoid
2200706f2543SmrgDRILock(ScreenPtr pScreen, int flags)
2201706f2543Smrg{
2202706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2203706f2543Smrg
2204706f2543Smrg    if(!pDRIPriv || !pDRIPriv->pLockRefCount) return;
2205706f2543Smrg
2206706f2543Smrg    if (!*pDRIPriv->pLockRefCount) {
2207706f2543Smrg        DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext, flags);
2208706f2543Smrg	*pDRIPriv->pLockingContext = pDRIPriv->myContext;
2209706f2543Smrg    } else if (*pDRIPriv->pLockingContext != pDRIPriv->myContext) {
2210706f2543Smrg	DRIDrvMsg(pScreen->myNum, X_ERROR,
2211706f2543Smrg		  "[DRI] Locking deadlock.\n"
2212706f2543Smrg		  "\tAlready locked with context %d,\n"
2213706f2543Smrg		  "\ttrying to lock with context %d.\n",
2214706f2543Smrg		  pDRIPriv->pLockingContext,
2215706f2543Smrg		  pDRIPriv->myContext);
2216706f2543Smrg    }
2217706f2543Smrg    (*pDRIPriv->pLockRefCount)++;
2218706f2543Smrg}
2219706f2543Smrg
2220706f2543Smrgvoid
2221706f2543SmrgDRIUnlock(ScreenPtr pScreen)
2222706f2543Smrg{
2223706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2224706f2543Smrg
2225706f2543Smrg    if(!pDRIPriv || !pDRIPriv->pLockRefCount) return;
2226706f2543Smrg
2227706f2543Smrg    if (*pDRIPriv->pLockRefCount > 0) {
2228706f2543Smrg	if (pDRIPriv->myContext != *pDRIPriv->pLockingContext) {
2229706f2543Smrg	    DRIDrvMsg(pScreen->myNum, X_ERROR,
2230706f2543Smrg		      "[DRI] Unlocking inconsistency:\n"
2231706f2543Smrg		      "\tContext %d trying to unlock lock held by context %d\n",
2232706f2543Smrg		      pDRIPriv->pLockingContext,
2233706f2543Smrg		      pDRIPriv->myContext);
2234706f2543Smrg	}
2235706f2543Smrg	(*pDRIPriv->pLockRefCount)--;
2236706f2543Smrg    } else {
2237706f2543Smrg        DRIDrvMsg(pScreen->myNum, X_ERROR,
2238706f2543Smrg		  "DRIUnlock called when not locked.\n");
2239706f2543Smrg        return;
2240706f2543Smrg    }
2241706f2543Smrg    if (! *pDRIPriv->pLockRefCount)
2242706f2543Smrg        DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext);
2243706f2543Smrg}
2244706f2543Smrg
2245706f2543Smrgvoid *
2246706f2543SmrgDRIGetSAREAPrivate(ScreenPtr pScreen)
2247706f2543Smrg{
2248706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2249706f2543Smrg    if (!pDRIPriv) return 0;
2250706f2543Smrg
2251706f2543Smrg    return (void *)(((char*)pDRIPriv->pSAREA)+sizeof(XF86DRISAREARec));
2252706f2543Smrg}
2253706f2543Smrg
2254706f2543Smrgdrm_context_t
2255706f2543SmrgDRIGetContext(ScreenPtr pScreen)
2256706f2543Smrg{
2257706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2258706f2543Smrg    if (!pDRIPriv) return 0;
2259706f2543Smrg
2260706f2543Smrg    return pDRIPriv->myContext;
2261706f2543Smrg}
2262706f2543Smrg
2263706f2543Smrgvoid
2264706f2543SmrgDRIGetTexOffsetFuncs(ScreenPtr pScreen,
2265706f2543Smrg		     DRITexOffsetStartProcPtr *texOffsetStartFunc,
2266706f2543Smrg		     DRITexOffsetFinishProcPtr *texOffsetFinishFunc)
2267706f2543Smrg{
2268706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2269706f2543Smrg
2270706f2543Smrg    if (!pDRIPriv) return;
2271706f2543Smrg
2272706f2543Smrg    *texOffsetStartFunc  = pDRIPriv->pDriverInfo->texOffsetStart;
2273706f2543Smrg    *texOffsetFinishFunc = pDRIPriv->pDriverInfo->texOffsetFinish;
2274706f2543Smrg}
2275706f2543Smrg
2276706f2543Smrg/* This lets get at the unwrapped functions so that they can correctly
2277706f2543Smrg * call the lowerlevel functions, and choose whether they will be
2278706f2543Smrg * called at every level of recursion (eg in validatetree).
2279706f2543Smrg */
2280706f2543SmrgDRIWrappedFuncsRec *
2281706f2543SmrgDRIGetWrappedFuncs(ScreenPtr pScreen)
2282706f2543Smrg{
2283706f2543Smrg    return &(DRI_SCREEN_PRIV(pScreen)->wrap);
2284706f2543Smrg}
2285706f2543Smrg
2286706f2543Smrg/* note that this returns the library version, not the protocol version */
2287706f2543Smrgvoid
2288706f2543SmrgDRIQueryVersion(int *majorVersion,
2289706f2543Smrg                int *minorVersion,
2290706f2543Smrg                int *patchVersion)
2291706f2543Smrg{
2292706f2543Smrg    *majorVersion = DRIINFO_MAJOR_VERSION;
2293706f2543Smrg    *minorVersion = DRIINFO_MINOR_VERSION;
2294706f2543Smrg    *patchVersion = DRIINFO_PATCH_VERSION;
2295706f2543Smrg}
2296706f2543Smrg
2297706f2543Smrgstatic void
2298706f2543Smrg_DRIAdjustFrame(ScrnInfoPtr pScrn, DRIScreenPrivPtr pDRIPriv, int x, int y)
2299706f2543Smrg{
2300706f2543Smrg    pDRIPriv->pSAREA->frame.x      = x;
2301706f2543Smrg    pDRIPriv->pSAREA->frame.y      = y;
2302706f2543Smrg    pDRIPriv->pSAREA->frame.width  = pScrn->frameX1 - x + 1;
2303706f2543Smrg    pDRIPriv->pSAREA->frame.height = pScrn->frameY1 - y + 1;
2304706f2543Smrg}
2305706f2543Smrg
2306706f2543Smrgvoid
2307706f2543SmrgDRIAdjustFrame(int scrnIndex, int x, int y, int flags)
2308706f2543Smrg{
2309706f2543Smrg    ScreenPtr        pScreen  = screenInfo.screens[scrnIndex];
2310706f2543Smrg    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
2311706f2543Smrg    ScrnInfoPtr      pScrn    = xf86Screens[pScreen->myNum];
2312706f2543Smrg    int              px, py;
2313706f2543Smrg
2314706f2543Smrg    if (!pDRIPriv || !pDRIPriv->pSAREA) {
2315706f2543Smrg	DRIDrvMsg(scrnIndex, X_ERROR, "[DRI] No SAREA (%p %p)\n",
2316706f2543Smrg		  pDRIPriv, pDRIPriv ? pDRIPriv->pSAREA : NULL);
2317706f2543Smrg	return;
2318706f2543Smrg    }
2319706f2543Smrg
2320706f2543Smrg    if (pDRIPriv->fullscreen) {
2321706f2543Smrg				/* Fix up frame */
2322706f2543Smrg	pScrn->frameX0 = pDRIPriv->pSAREA->frame.x;
2323706f2543Smrg	pScrn->frameY0 = pDRIPriv->pSAREA->frame.y;
2324706f2543Smrg	pScrn->frameX1 = pScrn->frameX0 + pDRIPriv->pSAREA->frame.width - 1;
2325706f2543Smrg	pScrn->frameY1 = pScrn->frameY0 + pDRIPriv->pSAREA->frame.height - 1;
2326706f2543Smrg
2327706f2543Smrg				/* Fix up cursor */
2328706f2543Smrg    miPointerGetPosition(inputInfo.pointer, &px, &py);
2329706f2543Smrg	if (px < pScrn->frameX0) px = pScrn->frameX0;
2330706f2543Smrg	if (px > pScrn->frameX1) px = pScrn->frameX1;
2331706f2543Smrg	if (py < pScrn->frameY0) py = pScrn->frameY0;
2332706f2543Smrg	if (py > pScrn->frameY1) py = pScrn->frameY1;
2333706f2543Smrg	pScreen->SetCursorPosition(inputInfo.pointer, pScreen, px, py, TRUE);
2334706f2543Smrg	return;
2335706f2543Smrg    }
2336706f2543Smrg
2337706f2543Smrg    if (pDRIPriv->wrap.AdjustFrame) {
2338706f2543Smrg	/* unwrap */
2339706f2543Smrg	pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame;
2340706f2543Smrg	/* call lower layers */
2341706f2543Smrg	(*pScrn->AdjustFrame)(scrnIndex, x, y, flags);
2342706f2543Smrg	/* rewrap */
2343706f2543Smrg	pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame;
2344706f2543Smrg	pScrn->AdjustFrame         = DRIAdjustFrame;
2345706f2543Smrg    }
2346706f2543Smrg
2347706f2543Smrg    _DRIAdjustFrame(pScrn, pDRIPriv, x, y);
2348706f2543Smrg}
2349706f2543Smrg
2350706f2543Smrg/*
2351706f2543Smrg * DRIMoveBuffersHelper swaps the regions rects in place leaving you
2352706f2543Smrg * a region with the rects in the order that you need to blit them,
2353706f2543Smrg * but it is possibly (likely) an invalid region afterwards.  If you
2354706f2543Smrg * need to use the region again for anything you have to call
2355706f2543Smrg * REGION_VALIDATE on it, or better yet, save a copy first.
2356706f2543Smrg */
2357706f2543Smrg
2358706f2543Smrgvoid
2359706f2543SmrgDRIMoveBuffersHelper(
2360706f2543Smrg   ScreenPtr pScreen,
2361706f2543Smrg   int dx,
2362706f2543Smrg   int dy,
2363706f2543Smrg   int *xdir,
2364706f2543Smrg   int *ydir,
2365706f2543Smrg   RegionPtr reg
2366706f2543Smrg)
2367706f2543Smrg{
2368706f2543Smrg   BoxPtr extents, pbox, firstBox, lastBox;
2369706f2543Smrg   BoxRec tmpBox;
2370706f2543Smrg   int y, nbox;
2371706f2543Smrg
2372706f2543Smrg   extents = RegionExtents(reg);
2373706f2543Smrg   nbox = RegionNumRects(reg);
2374706f2543Smrg   pbox = RegionRects(reg);
2375706f2543Smrg
2376706f2543Smrg   if((dy > 0) && (dy < (extents->y2 - extents->y1))) {
2377706f2543Smrg     *ydir = -1;
2378706f2543Smrg     if(nbox > 1) {
2379706f2543Smrg        firstBox = pbox;
2380706f2543Smrg        lastBox = pbox + nbox - 1;
2381706f2543Smrg        while((unsigned long)firstBox < (unsigned long)lastBox) {
2382706f2543Smrg           tmpBox = *firstBox;
2383706f2543Smrg           *firstBox = *lastBox;
2384706f2543Smrg           *lastBox = tmpBox;
2385706f2543Smrg           firstBox++;
2386706f2543Smrg           lastBox--;
2387706f2543Smrg        }
2388706f2543Smrg     }
2389706f2543Smrg   } else *ydir = 1;
2390706f2543Smrg
2391706f2543Smrg   if((dx > 0) && (dx < (extents->x2 - extents->x1))) {
2392706f2543Smrg     *xdir = -1;
2393706f2543Smrg     if(nbox > 1) {
2394706f2543Smrg        firstBox = lastBox = pbox;
2395706f2543Smrg        y = pbox->y1;
2396706f2543Smrg        while(--nbox) {
2397706f2543Smrg           pbox++;
2398706f2543Smrg           if(pbox->y1 == y) lastBox++;
2399706f2543Smrg           else {
2400706f2543Smrg              while((unsigned long)firstBox < (unsigned long)lastBox) {
2401706f2543Smrg                 tmpBox = *firstBox;
2402706f2543Smrg                 *firstBox = *lastBox;
2403706f2543Smrg                 *lastBox = tmpBox;
2404706f2543Smrg                 firstBox++;
2405706f2543Smrg                 lastBox--;
2406706f2543Smrg              }
2407706f2543Smrg
2408706f2543Smrg              firstBox = lastBox = pbox;
2409706f2543Smrg              y = pbox->y1;
2410706f2543Smrg           }
2411706f2543Smrg         }
2412706f2543Smrg         while((unsigned long)firstBox < (unsigned long)lastBox) {
2413706f2543Smrg           tmpBox = *firstBox;
2414706f2543Smrg           *firstBox = *lastBox;
2415706f2543Smrg           *lastBox = tmpBox;
2416706f2543Smrg           firstBox++;
2417706f2543Smrg           lastBox--;
2418706f2543Smrg        }
2419706f2543Smrg     }
2420706f2543Smrg   } else *xdir = 1;
2421706f2543Smrg
2422706f2543Smrg}
2423706f2543Smrg
2424706f2543Smrgchar *
2425706f2543SmrgDRICreatePCIBusID(const struct pci_device * dev)
2426706f2543Smrg{
2427706f2543Smrg    char *busID;
2428706f2543Smrg
2429706f2543Smrg    if (asprintf(&busID, "pci:%04x:%02x:%02x.%d",
2430706f2543Smrg		 dev->domain, dev->bus, dev->dev, dev->func) == -1)
2431706f2543Smrg	return NULL;
2432706f2543Smrg
2433706f2543Smrg    return busID;
2434706f2543Smrg}
2435706f2543Smrg
2436706f2543Smrgstatic void drmSIGIOHandler(int interrupt, void *closure)
2437706f2543Smrg{
2438706f2543Smrg    unsigned long key;
2439706f2543Smrg    void          *value;
2440706f2543Smrg    ssize_t       count;
2441706f2543Smrg    drm_ctx_t     ctx;
2442706f2543Smrg    typedef void  (*_drmCallback)(int, void *, void *);
2443706f2543Smrg    char          buf[256];
2444706f2543Smrg    drm_context_t    old;
2445706f2543Smrg    drm_context_t    new;
2446706f2543Smrg    void          *oldctx;
2447706f2543Smrg    void          *newctx;
2448706f2543Smrg    char          *pt;
2449706f2543Smrg    drmHashEntry  *entry;
2450706f2543Smrg    void *hash_table;
2451706f2543Smrg
2452706f2543Smrg    hash_table = drmGetHashTable();
2453706f2543Smrg
2454706f2543Smrg    if (!hash_table) return;
2455706f2543Smrg    if (drmHashFirst(hash_table, &key, &value)) {
2456706f2543Smrg	entry = value;
2457706f2543Smrg	do {
2458706f2543Smrg#if 0
2459706f2543Smrg	    fprintf(stderr, "Trying %d\n", entry->fd);
2460706f2543Smrg#endif
2461706f2543Smrg	    if ((count = read(entry->fd, buf, sizeof(buf) - 1)) > 0) {
2462706f2543Smrg		buf[count] = '\0';
2463706f2543Smrg#if 0
2464706f2543Smrg		fprintf(stderr, "Got %s\n", buf);
2465706f2543Smrg#endif
2466706f2543Smrg
2467706f2543Smrg		for (pt = buf; *pt != ' '; ++pt); /* Find first space */
2468706f2543Smrg		++pt;
2469706f2543Smrg		old    = strtol(pt, &pt, 0);
2470706f2543Smrg		new    = strtol(pt, NULL, 0);
2471706f2543Smrg		oldctx = drmGetContextTag(entry->fd, old);
2472706f2543Smrg		newctx = drmGetContextTag(entry->fd, new);
2473706f2543Smrg#if 0
2474706f2543Smrg		fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx);
2475706f2543Smrg#endif
2476706f2543Smrg		((_drmCallback)entry->f)(entry->fd, oldctx, newctx);
2477706f2543Smrg		ctx.handle = new;
2478706f2543Smrg		ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx);
2479706f2543Smrg	    }
2480706f2543Smrg	} while (drmHashNext(hash_table, &key, &value));
2481706f2543Smrg    }
2482706f2543Smrg}
2483706f2543Smrg
2484706f2543Smrg
2485706f2543Smrgint drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *))
2486706f2543Smrg{
2487706f2543Smrg    drmHashEntry     *entry;
2488706f2543Smrg
2489706f2543Smrg    entry     = drmGetEntry(fd);
2490706f2543Smrg    entry->f  = f;
2491706f2543Smrg
2492706f2543Smrg    return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0);
2493706f2543Smrg}
2494706f2543Smrg
2495706f2543Smrgint drmRemoveSIGIOHandler(int fd)
2496706f2543Smrg{
2497706f2543Smrg    drmHashEntry     *entry = drmGetEntry(fd);
2498706f2543Smrg
2499706f2543Smrg    entry->f = NULL;
2500706f2543Smrg
2501706f2543Smrg    return xf86RemoveSIGIOHandler(fd);
2502706f2543Smrg}
2503