1/************************************************************************** 2 3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 4Copyright 2000 VA Linux Systems, Inc. 5All Rights Reserved. 6 7Permission is hereby granted, free of charge, to any person obtaining a 8copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sub license, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice (including the 16next paragraph) shall be included in all copies or substantial portions 17of the Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 27**************************************************************************/ 28 29/* 30 * Authors: 31 * Jens Owen <jens@tungstengraphics.com> 32 * Rickard E. (Rik) Faith <faith@valinux.com> 33 * 34 */ 35 36#ifdef HAVE_XORG_CONFIG_H 37#include <xorg-config.h> 38#endif 39 40#include "xf86.h" 41#include <sys/time.h> 42#include <unistd.h> 43#include <string.h> 44#include <stdio.h> 45#include <sys/ioctl.h> 46#include <errno.h> 47 48#include <X11/X.h> 49#include <X11/Xproto.h> 50#include "xf86drm.h" 51#include "misc.h" 52#include "dixstruct.h" 53#include "extnsionst.h" 54#include "extinit.h" 55#include "colormapst.h" 56#include "cursorstr.h" 57#include "scrnintstr.h" 58#include "windowstr.h" 59#include "servermd.h" 60#define _XF86DRI_SERVER_ 61#include <X11/dri/xf86driproto.h> 62#include "swaprep.h" 63#include "xf86str.h" 64#include "dri.h" 65#include "sarea.h" 66#include "dristruct.h" 67#include "mi.h" 68#include "mipointer.h" 69#include "xf86_OSproc.h" 70#include "inputstr.h" 71#include "xf86VGAarbiter.h" 72#include "xf86Extensions.h" 73 74static int DRIEntPrivIndex = -1; 75static DevPrivateKeyRec DRIScreenPrivKeyRec; 76 77#define DRIScreenPrivKey (&DRIScreenPrivKeyRec) 78static DevPrivateKeyRec DRIWindowPrivKeyRec; 79 80#define DRIWindowPrivKey (&DRIWindowPrivKeyRec) 81static unsigned long DRIGeneration = 0; 82static unsigned int DRIDrawableValidationStamp = 0; 83 84static RESTYPE DRIDrawablePrivResType; 85static RESTYPE DRIContextPrivResType; 86static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv); 87 88drmServerInfo DRIDRMServerInfo; 89 90 /* Wrapper just like xf86DrvMsg, but 91 without the verbosity level checking. 92 This will make it easy to turn off some 93 messages later, based on verbosity 94 level. */ 95 96/* 97 * Since we're already referencing things from the XFree86 common layer in 98 * this file, we'd might as well just call xf86VDrvMsgVerb, and have 99 * consistent message formatting. The verbosity of these messages can be 100 * easily changed here. 101 */ 102#define DRI_MSG_VERBOSITY 1 103 104static void 105DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...) 106 _X_ATTRIBUTE_PRINTF(3,4); 107 108static void 109DRIDrvMsg(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 118static void 119DRIOpenDRMCleanup(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 134int 135DRIMasterFD(ScrnInfoPtr pScrn) 136{ 137 return DRI_ENT_PRIV(pScrn)->drmFD; 138} 139 140void * 141DRIMasterSareaPointer(ScrnInfoPtr pScrn) 142{ 143 return DRI_ENT_PRIV(pScrn)->pLSAREA; 144} 145 146drm_handle_t 147DRIMasterSareaHandle(ScrnInfoPtr pScrn) 148{ 149 return DRI_ENT_PRIV(pScrn)->hLSAREA; 150} 151 152Bool 153DRIOpenDRMMaster(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 278static void 279 DRIClipNotifyAllDrawables(ScreenPtr pScreen); 280 281static void 282dri_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 293static void 294drmSIGIOHandler(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 334static int 335drmInstallSIGIOHandler(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 345static int 346drmRemoveSIGIOHandler(int fd) 347{ 348 drmHashEntry *entry = drmGetEntry(fd); 349 350 entry->f = NULL; 351 352 return xf86RemoveSIGIOHandler(fd); 353} 354 355Bool 356DRIScreenInit(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 633Bool 634DRIFinishScreenInit(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 672void 673DRICloseScreen(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 789static int 790dri_drm_debug_print(const char *format, va_list ap) 791 _X_ATTRIBUTE_PRINTF(1,0); 792 793static int 794dri_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 800static void 801dri_drm_get_perms(gid_t * group, mode_t * mode) 802{ 803 *group = xf86ConfigDRI.group; 804 *mode = xf86ConfigDRI.mode; 805} 806 807drmServerInfo DRIDRMServerInfo = { 808 dri_drm_debug_print, 809 xf86LoadKernelModule, 810 dri_drm_get_perms, 811}; 812 813Bool 814DRIExtensionInit(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 833void 834DRIReset(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 845Bool 846DRIQueryDirectRenderingCapable(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 858Bool 859DRIOpenConnection(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 869Bool 870DRIAuthConnection(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 879Bool 880DRICloseConnection(ScreenPtr pScreen) 881{ 882 return TRUE; 883} 884 885Bool 886DRIGetClientDriverName(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 913DRIContextPrivPtr 914DRICreateContextPriv(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 926DRIContextPrivPtr 927DRICreateContextPrivFromHandle(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 968Bool 969DRIDestroyContextPriv(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 996static Bool 997DRICreateDummyContext(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 1024static void 1025DRIDestroyDummyContext(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 1045Bool 1046DRICreateContext(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 1083Bool 1084DRIDestroyContext(ScreenPtr pScreen, XID context) 1085{ 1086 FreeResourceByType(context, DRIContextPrivResType, FALSE); 1087 1088 return TRUE; 1089} 1090 1091/* DRIContextPrivDelete is called by the resource manager. */ 1092Bool 1093DRIContextPrivDelete(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 */ 1116static void 1117DRIClipNotifyAllDrawables(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 1127static void 1128DRITransitionToSharedBuffers(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 1139static void 1140DRITransitionToPrivateBuffers(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 1151static void 1152DRITransitionTo3d(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 1163static void 1164DRITransitionTo2d(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 1175static int 1176DRIDCNTreeTraversal(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 1203static void 1204DRIDriverClipNotify(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 1224static void 1225DRIIncreaseNumberVisible(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 1243static void 1244DRIDecreaseNumberVisible(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 1262Bool 1263DRICreateDrawable(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 1330static void 1331DRIDrawablePrivDestroy(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 1363static Bool 1364DRIDestroyDrawableCB(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 1376Bool 1377DRIDestroyDrawable(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 1392Bool 1393DRIDrawablePrivDelete(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 1420Bool 1421DRIGetDrawableInfo(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 1597Bool 1598DRIGetDeviceInfo(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 1616DRIInfoPtr 1617DRICreateInfoRec(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 1642void 1643DRIDestroyInfoRec(DRIInfoPtr DRIInfo) 1644{ 1645 free(DRIInfo->busIdString); 1646 free((char *) DRIInfo); 1647} 1648 1649void 1650DRIWakeupHandler(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 1663void 1664DRIBlockHandler(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 1677void 1678DRIDoWakeupHandler(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 1694void 1695DRIDoBlockHandler(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 1716void 1717DRISwapContext(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 /* useful 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 1864void * 1865DRIGetContextStore(DRIContextPrivPtr context) 1866{ 1867 return ((void *) context->pContextStore); 1868} 1869 1870void 1871DRIWindowExposures(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 1897static int 1898DRITreeTraversal(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 1919Bool 1920DRIDestroyWindow(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 1944void 1945DRICopyWindow(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 1988static void 1989DRIGetSecs(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 1999static unsigned long 2000DRIComputeMilliSeconds(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 2010static void 2011DRISpinLockTimeout(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 2047static void 2048DRILockTree(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 2089void 2090DRIClipNotify(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 2139CARD32 2140DRIGetDrawableIndex(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 2157unsigned int 2158DRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index) 2159{ 2160 DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); 2161 2162 return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp; 2163} 2164 2165void 2166DRIPrintDrawableLock(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 2173void 2174DRILock(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 2196void 2197DRIUnlock(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 2222void * 2223DRIGetSAREAPrivate(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 2233drm_context_t 2234DRIGetContext(ScreenPtr pScreen) 2235{ 2236 DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); 2237 2238 if (!pDRIPriv) 2239 return 0; 2240 2241 return pDRIPriv->myContext; 2242} 2243 2244void 2245DRIGetTexOffsetFuncs(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 */ 2262DRIWrappedFuncsRec * 2263DRIGetWrappedFuncs(ScreenPtr pScreen) 2264{ 2265 return &(DRI_SCREEN_PRIV(pScreen)->wrap); 2266} 2267 2268/* note that this returns the library version, not the protocol version */ 2269void 2270DRIQueryVersion(int *majorVersion, int *minorVersion, int *patchVersion) 2271{ 2272 *majorVersion = DRIINFO_MAJOR_VERSION; 2273 *minorVersion = DRIINFO_MINOR_VERSION; 2274 *patchVersion = DRIINFO_PATCH_VERSION; 2275} 2276 2277static void 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 2286void 2287DRIAdjustFrame(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 2343void 2344DRIMoveBuffersHelper(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