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(®);
1957 pDRIPriv->nrWalked = 0;
1958 TraverseTree(pWin, DRITreeTraversal, (void *) (®));
1959
1960 if (RegionNotEmpty(®)) {
1961 RegionTranslate(®, ptOldOrg.x - pWin->drawable.x,
1962 ptOldOrg.y - pWin->drawable.y);
1963 RegionIntersect(®, ®, prgnSrc);
1964
1965 /* The MoveBuffers interface is not ideal */
1966 (*pDRIPriv->pDriverInfo->MoveBuffers) (pWin, ptOldOrg, ®,
1967 pDRIPriv->pDriverInfo->
1968 ddxDrawableTableEntry);
1969 }
1970
1971 RegionUninit(®);
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