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