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