1/* 2 * Copyright © 2007, 2008 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Soft- 6 * ware"), to deal in the Software without restriction, including without 7 * limitation the rights to use, copy, modify, merge, publish, distribute, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, provided that the above copyright 10 * notice(s) and this permission notice appear in all copies of the Soft- 11 * ware and that both the above copyright notice(s) and this permission 12 * notice appear in supporting documentation. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 22 * MANCE OF THIS SOFTWARE. 23 * 24 * Except as contained in this notice, the name of a copyright holder shall 25 * not be used in advertising or otherwise to promote the sale, use or 26 * other dealings in this Software without prior written authorization of 27 * the copyright holder. 28 * 29 * Authors: 30 * Kristian Høgsberg (krh@redhat.com) 31 */ 32 33#ifdef HAVE_XORG_CONFIG_H 34#include <xorg-config.h> 35#endif 36 37#include <errno.h> 38#ifdef WITH_LIBDRM 39#include <xf86drm.h> 40#endif 41#include "xf86Module.h" 42#include "list.h" 43#include "scrnintstr.h" 44#include "windowstr.h" 45#include "dixstruct.h" 46#include "dri2.h" 47#include "xf86VGAarbiter.h" 48 49#include "xf86.h" 50 51CARD8 dri2_major; /* version of DRI2 supported by DDX */ 52CARD8 dri2_minor; 53 54static DevPrivateKeyRec dri2ScreenPrivateKeyRec; 55#define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec) 56 57static DevPrivateKeyRec dri2WindowPrivateKeyRec; 58#define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec) 59 60static DevPrivateKeyRec dri2PixmapPrivateKeyRec; 61#define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec) 62 63static RESTYPE dri2DrawableRes; 64 65typedef struct _DRI2Screen *DRI2ScreenPtr; 66 67typedef struct _DRI2Drawable { 68 DRI2ScreenPtr dri2_screen; 69 DrawablePtr drawable; 70 struct list reference_list; 71 int width; 72 int height; 73 DRI2BufferPtr *buffers; 74 int bufferCount; 75 unsigned int swapsPending; 76 ClientPtr blockedClient; 77 Bool blockedOnMsc; 78 int swap_interval; 79 CARD64 swap_count; 80 int64_t target_sbc; /* -1 means no SBC wait outstanding */ 81 CARD64 last_swap_target; /* most recently queued swap target */ 82 CARD64 last_swap_msc; /* msc at completion of most recent swap */ 83 CARD64 last_swap_ust; /* ust at completion of most recent swap */ 84 int swap_limit; /* for N-buffering */ 85 unsigned long serialNumber; 86} DRI2DrawableRec, *DRI2DrawablePtr; 87 88typedef struct _DRI2Screen { 89 ScreenPtr screen; 90 int refcnt; 91 unsigned int numDrivers; 92 const char **driverNames; 93 const char *deviceName; 94 int fd; 95 unsigned int lastSequence; 96 97 DRI2CreateBufferProcPtr CreateBuffer; 98 DRI2DestroyBufferProcPtr DestroyBuffer; 99 DRI2CopyRegionProcPtr CopyRegion; 100 DRI2ScheduleSwapProcPtr ScheduleSwap; 101 DRI2GetMSCProcPtr GetMSC; 102 DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC; 103 DRI2AuthMagicProcPtr AuthMagic; 104 105 HandleExposuresProcPtr HandleExposures; 106 107 ConfigNotifyProcPtr ConfigNotify; 108} DRI2ScreenRec; 109 110static DRI2ScreenPtr 111DRI2GetScreen(ScreenPtr pScreen) 112{ 113 return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey); 114} 115 116static DRI2DrawablePtr 117DRI2GetDrawable(DrawablePtr pDraw) 118{ 119 WindowPtr pWin; 120 PixmapPtr pPixmap; 121 122 switch (pDraw->type) { 123 case DRAWABLE_WINDOW: 124 pWin = (WindowPtr) pDraw; 125 return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey); 126 case DRAWABLE_PIXMAP: 127 pPixmap = (PixmapPtr) pDraw; 128 return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey); 129 default: 130 return NULL; 131 } 132} 133 134static unsigned long 135DRI2DrawableSerial(DrawablePtr pDraw) 136{ 137 ScreenPtr pScreen = pDraw->pScreen; 138 PixmapPtr pPix; 139 140 if (pDraw->type != DRAWABLE_WINDOW) 141 return pDraw->serialNumber; 142 143 pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw); 144 return pPix->drawable.serialNumber; 145} 146 147static DRI2DrawablePtr 148DRI2AllocateDrawable(DrawablePtr pDraw) 149{ 150 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 151 DRI2DrawablePtr pPriv; 152 CARD64 ust; 153 WindowPtr pWin; 154 PixmapPtr pPixmap; 155 156 pPriv = malloc(sizeof *pPriv); 157 if (pPriv == NULL) 158 return NULL; 159 160 pPriv->dri2_screen = ds; 161 pPriv->drawable = pDraw; 162 pPriv->width = pDraw->width; 163 pPriv->height = pDraw->height; 164 pPriv->buffers = NULL; 165 pPriv->bufferCount = 0; 166 pPriv->swapsPending = 0; 167 pPriv->blockedClient = NULL; 168 pPriv->blockedOnMsc = FALSE; 169 pPriv->swap_count = 0; 170 pPriv->target_sbc = -1; 171 pPriv->swap_interval = 1; 172 /* Initialize last swap target from DDX if possible */ 173 if (!ds->GetMSC || !(*ds->GetMSC)(pDraw, &ust, &pPriv->last_swap_target)) 174 pPriv->last_swap_target = 0; 175 176 pPriv->swap_limit = 1; /* default to double buffering */ 177 pPriv->last_swap_msc = 0; 178 pPriv->last_swap_ust = 0; 179 list_init(&pPriv->reference_list); 180 pPriv->serialNumber = DRI2DrawableSerial(pDraw); 181 182 if (pDraw->type == DRAWABLE_WINDOW) { 183 pWin = (WindowPtr) pDraw; 184 dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv); 185 } else { 186 pPixmap = (PixmapPtr) pDraw; 187 dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv); 188 } 189 190 return pPriv; 191} 192 193typedef struct DRI2DrawableRefRec { 194 XID id; 195 XID dri2_id; 196 DRI2InvalidateProcPtr invalidate; 197 void *priv; 198 struct list link; 199} DRI2DrawableRefRec, *DRI2DrawableRefPtr; 200 201static DRI2DrawableRefPtr 202DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id) 203{ 204 DRI2DrawableRefPtr ref = NULL; 205 206 list_for_each_entry(ref, &pPriv->reference_list, link) { 207 if (ref->id == id) 208 return ref; 209 } 210 211 return NULL; 212} 213 214static int 215DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id, 216 DRI2InvalidateProcPtr invalidate, void *priv) 217{ 218 DRI2DrawableRefPtr ref; 219 220 ref = malloc(sizeof *ref); 221 if (ref == NULL) 222 return BadAlloc; 223 224 if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) { 225 free(ref); 226 return BadAlloc; 227 } 228 if (!DRI2LookupDrawableRef(pPriv, id)) 229 if (!AddResource(id, dri2DrawableRes, pPriv)) { 230 FreeResourceByType(dri2_id, dri2DrawableRes, TRUE); 231 free(ref); 232 return BadAlloc; 233 } 234 235 ref->id = id; 236 ref->dri2_id = dri2_id; 237 ref->invalidate = invalidate; 238 ref->priv = priv; 239 list_add(&ref->link, &pPriv->reference_list); 240 241 return Success; 242} 243 244int 245DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id, 246 DRI2InvalidateProcPtr invalidate, void *priv) 247{ 248 DRI2DrawablePtr pPriv; 249 XID dri2_id; 250 int rc; 251 252 pPriv = DRI2GetDrawable(pDraw); 253 if (pPriv == NULL) 254 pPriv = DRI2AllocateDrawable(pDraw); 255 if (pPriv == NULL) 256 return BadAlloc; 257 258 dri2_id = FakeClientID(client->index); 259 rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv); 260 if (rc != Success) 261 return rc; 262 263 return Success; 264} 265 266static int DRI2DrawableGone(pointer p, XID id) 267{ 268 DRI2DrawablePtr pPriv = p; 269 DRI2ScreenPtr ds = pPriv->dri2_screen; 270 DRI2DrawableRefPtr ref = NULL, next; 271 WindowPtr pWin; 272 PixmapPtr pPixmap; 273 DrawablePtr pDraw; 274 int i; 275 276 list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) { 277 if (ref->dri2_id == id) { 278 list_del(&ref->link); 279 /* If this was the last ref under this X drawable XID, 280 * unregister the X drawable resource. */ 281 if (!DRI2LookupDrawableRef(pPriv, ref->id)) 282 FreeResourceByType(ref->id, dri2DrawableRes, TRUE); 283 free(ref); 284 break; 285 } 286 287 if (ref->id == id) { 288 list_del(&ref->link); 289 FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE); 290 free(ref); 291 } 292 } 293 294 if (!list_is_empty(&pPriv->reference_list)) 295 return Success; 296 297 pDraw = pPriv->drawable; 298 if (pDraw->type == DRAWABLE_WINDOW) { 299 pWin = (WindowPtr) pDraw; 300 dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL); 301 } else { 302 pPixmap = (PixmapPtr) pDraw; 303 dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL); 304 } 305 306 if (pPriv->buffers != NULL) { 307 for (i = 0; i < pPriv->bufferCount; i++) 308 (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); 309 310 free(pPriv->buffers); 311 } 312 313 free(pPriv); 314 315 return Success; 316} 317 318static int 319find_attachment(DRI2DrawablePtr pPriv, unsigned attachment) 320{ 321 int i; 322 323 if (pPriv->buffers == NULL) { 324 return -1; 325 } 326 327 for (i = 0; i < pPriv->bufferCount; i++) { 328 if ((pPriv->buffers[i] != NULL) 329 && (pPriv->buffers[i]->attachment == attachment)) { 330 return i; 331 } 332 } 333 334 return -1; 335} 336 337static Bool 338allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, 339 DRI2DrawablePtr pPriv, 340 unsigned int attachment, unsigned int format, 341 int dimensions_match, DRI2BufferPtr *buffer) 342{ 343 int old_buf = find_attachment(pPriv, attachment); 344 345 if ((old_buf < 0) 346 || !dimensions_match 347 || (pPriv->buffers[old_buf]->format != format)) { 348 *buffer = (*ds->CreateBuffer)(pDraw, attachment, format); 349 pPriv->serialNumber = DRI2DrawableSerial(pDraw); 350 return TRUE; 351 352 } else { 353 *buffer = pPriv->buffers[old_buf]; 354 pPriv->buffers[old_buf] = NULL; 355 return FALSE; 356 } 357} 358 359static void 360update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw, 361 DRI2BufferPtr *buffers, int *out_count, int *width, int *height) 362{ 363 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 364 int i; 365 366 if (pPriv->buffers != NULL) { 367 for (i = 0; i < pPriv->bufferCount; i++) { 368 if (pPriv->buffers[i] != NULL) { 369 (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); 370 } 371 } 372 373 free(pPriv->buffers); 374 } 375 376 pPriv->buffers = buffers; 377 pPriv->bufferCount = *out_count; 378 pPriv->width = pDraw->width; 379 pPriv->height = pDraw->height; 380 *width = pPriv->width; 381 *height = pPriv->height; 382} 383 384static DRI2BufferPtr * 385do_get_buffers(DrawablePtr pDraw, int *width, int *height, 386 unsigned int *attachments, int count, int *out_count, 387 int has_format) 388{ 389 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 390 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 391 DRI2BufferPtr *buffers; 392 int need_real_front = 0; 393 int need_fake_front = 0; 394 int have_fake_front = 0; 395 int front_format = 0; 396 int dimensions_match; 397 int buffers_changed = 0; 398 int i; 399 400 if (!pPriv) { 401 *width = pDraw->width; 402 *height = pDraw->height; 403 *out_count = 0; 404 return NULL; 405 } 406 407 dimensions_match = (pDraw->width == pPriv->width) 408 && (pDraw->height == pPriv->height) 409 && (pPriv->serialNumber == DRI2DrawableSerial(pDraw)); 410 411 buffers = calloc((count + 1), sizeof(buffers[0])); 412 413 for (i = 0; i < count; i++) { 414 const unsigned attachment = *(attachments++); 415 const unsigned format = (has_format) ? *(attachments++) : 0; 416 417 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, 418 format, dimensions_match, 419 &buffers[i])) 420 buffers_changed = 1; 421 422 if (buffers[i] == NULL) 423 goto err_out; 424 425 /* If the drawable is a window and the front-buffer is requested, 426 * silently add the fake front-buffer to the list of requested 427 * attachments. The counting logic in the loop accounts for the case 428 * where the client requests both the fake and real front-buffer. 429 */ 430 if (attachment == DRI2BufferBackLeft) { 431 need_real_front++; 432 front_format = format; 433 } 434 435 if (attachment == DRI2BufferFrontLeft) { 436 need_real_front--; 437 front_format = format; 438 439 if (pDraw->type == DRAWABLE_WINDOW) { 440 need_fake_front++; 441 } 442 } 443 444 if (pDraw->type == DRAWABLE_WINDOW) { 445 if (attachment == DRI2BufferFakeFrontLeft) { 446 need_fake_front--; 447 have_fake_front = 1; 448 } 449 } 450 } 451 452 if (need_real_front > 0) { 453 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft, 454 front_format, dimensions_match, 455 &buffers[i])) 456 buffers_changed = 1; 457 458 if (buffers[i] == NULL) 459 goto err_out; 460 i++; 461 } 462 463 if (need_fake_front > 0) { 464 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft, 465 front_format, dimensions_match, 466 &buffers[i])) 467 buffers_changed = 1; 468 469 if (buffers[i] == NULL) 470 goto err_out; 471 472 i++; 473 have_fake_front = 1; 474 } 475 476 *out_count = i; 477 478 update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height); 479 480 /* If the client is getting a fake front-buffer, pre-fill it with the 481 * contents of the real front-buffer. This ensures correct operation of 482 * applications that call glXWaitX before calling glDrawBuffer. 483 */ 484 if (have_fake_front && buffers_changed) { 485 BoxRec box; 486 RegionRec region; 487 488 box.x1 = 0; 489 box.y1 = 0; 490 box.x2 = pPriv->width; 491 box.y2 = pPriv->height; 492 RegionInit(®ion, &box, 0); 493 494 DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 495 DRI2BufferFrontLeft); 496 } 497 498 return pPriv->buffers; 499 500err_out: 501 502 *out_count = 0; 503 504 for (i = 0; i < count; i++) { 505 if (buffers[i] != NULL) 506 (*ds->DestroyBuffer)(pDraw, buffers[i]); 507 } 508 509 free(buffers); 510 buffers = NULL; 511 512 update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height); 513 514 return buffers; 515} 516 517DRI2BufferPtr * 518DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height, 519 unsigned int *attachments, int count, int *out_count) 520{ 521 return do_get_buffers(pDraw, width, height, attachments, count, 522 out_count, FALSE); 523} 524 525DRI2BufferPtr * 526DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, 527 unsigned int *attachments, int count, int *out_count) 528{ 529 return do_get_buffers(pDraw, width, height, attachments, count, 530 out_count, TRUE); 531} 532 533static void 534DRI2InvalidateDrawable(DrawablePtr pDraw) 535{ 536 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 537 DRI2DrawableRefPtr ref = NULL; 538 539 if (!pPriv) 540 return; 541 542 list_for_each_entry(ref, &pPriv->reference_list, link) 543 ref->invalidate(pDraw, ref->priv); 544} 545 546/* 547 * In the direct rendered case, we throttle the clients that have more 548 * than their share of outstanding swaps (and thus busy buffers) when a 549 * new GetBuffers request is received. In the AIGLX case, we allow the 550 * client to get the new buffers, but throttle when the next GLX request 551 * comes in (see __glXDRIcontextWait()). 552 */ 553Bool 554DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw) 555{ 556 DRI2DrawablePtr pPriv; 557 558 pPriv = DRI2GetDrawable(pDraw); 559 if (pPriv == NULL) 560 return FALSE; 561 562 /* Throttle to swap limit */ 563 if ((pPriv->swapsPending >= pPriv->swap_limit) && 564 !pPriv->blockedClient) { 565 ResetCurrentRequest(client); 566 client->sequence--; 567 IgnoreClient(client); 568 pPriv->blockedClient = client; 569 return TRUE; 570 } 571 572 return FALSE; 573} 574 575static void 576__DRI2BlockClient(ClientPtr client, DRI2DrawablePtr pPriv) 577{ 578 if (pPriv->blockedClient == NULL) { 579 IgnoreClient(client); 580 pPriv->blockedClient = client; 581 } 582} 583 584void 585DRI2BlockClient(ClientPtr client, DrawablePtr pDraw) 586{ 587 DRI2DrawablePtr pPriv; 588 589 pPriv = DRI2GetDrawable(pDraw); 590 if (pPriv == NULL) 591 return; 592 593 __DRI2BlockClient(client, pPriv); 594 pPriv->blockedOnMsc = TRUE; 595} 596 597int 598DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, 599 unsigned int dest, unsigned int src) 600{ 601 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 602 DRI2DrawablePtr pPriv; 603 DRI2BufferPtr pDestBuffer, pSrcBuffer; 604 int i; 605 606 pPriv = DRI2GetDrawable(pDraw); 607 if (pPriv == NULL) 608 return BadDrawable; 609 610 pDestBuffer = NULL; 611 pSrcBuffer = NULL; 612 for (i = 0; i < pPriv->bufferCount; i++) 613 { 614 if (pPriv->buffers[i]->attachment == dest) 615 pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 616 if (pPriv->buffers[i]->attachment == src) 617 pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 618 } 619 if (pSrcBuffer == NULL || pDestBuffer == NULL) 620 return BadValue; 621 622 (*ds->CopyRegion)(pDraw, pRegion, pDestBuffer, pSrcBuffer); 623 624 return Success; 625} 626 627/* Can this drawable be page flipped? */ 628Bool 629DRI2CanFlip(DrawablePtr pDraw) 630{ 631 ScreenPtr pScreen = pDraw->pScreen; 632 WindowPtr pWin, pRoot; 633 PixmapPtr pWinPixmap, pRootPixmap; 634 635 if (pDraw->type == DRAWABLE_PIXMAP) 636 return TRUE; 637 638 pRoot = pScreen->root; 639 pRootPixmap = pScreen->GetWindowPixmap(pRoot); 640 641 pWin = (WindowPtr) pDraw; 642 pWinPixmap = pScreen->GetWindowPixmap(pWin); 643 if (pRootPixmap != pWinPixmap) 644 return FALSE; 645 if (!RegionEqual(&pWin->clipList, &pRoot->winSize)) 646 return FALSE; 647 648 /* Does the window match the pixmap exactly? */ 649 if (pDraw->x != 0 || 650 pDraw->y != 0 || 651#ifdef COMPOSITE 652 pDraw->x != pWinPixmap->screen_x || 653 pDraw->y != pWinPixmap->screen_y || 654#endif 655 pDraw->width != pWinPixmap->drawable.width || 656 pDraw->height != pWinPixmap->drawable.height) 657 return FALSE; 658 659 return TRUE; 660} 661 662/* Can we do a pixmap exchange instead of a blit? */ 663Bool 664DRI2CanExchange(DrawablePtr pDraw) 665{ 666 return FALSE; 667} 668 669void 670DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, 671 unsigned int tv_sec, unsigned int tv_usec) 672{ 673 DRI2DrawablePtr pPriv; 674 675 pPriv = DRI2GetDrawable(pDraw); 676 if (pPriv == NULL) 677 return; 678 679 ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, 680 frame, pPriv->swap_count); 681 682 if (pPriv->blockedClient) 683 AttendClient(pPriv->blockedClient); 684 685 pPriv->blockedClient = NULL; 686 pPriv->blockedOnMsc = FALSE; 687} 688 689static void 690DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame, 691 unsigned int tv_sec, unsigned int tv_usec) 692{ 693 ScreenPtr pScreen = pDraw->pScreen; 694 DRI2DrawablePtr pPriv; 695 696 pPriv = DRI2GetDrawable(pDraw); 697 if (pPriv == NULL) { 698 xf86DrvMsg(pScreen->myNum, X_ERROR, 699 "[DRI2] %s: bad drawable\n", __func__); 700 return; 701 } 702 703 /* 704 * Swap completed. 705 * Wake the client iff: 706 * - it was waiting on SBC 707 * - was blocked due to GLX make current 708 * - was blocked due to swap throttling 709 * - is not blocked due to an MSC wait 710 */ 711 if (pPriv->target_sbc != -1 && 712 pPriv->target_sbc <= pPriv->swap_count) { 713 ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, 714 frame, pPriv->swap_count); 715 pPriv->target_sbc = -1; 716 717 AttendClient(pPriv->blockedClient); 718 pPriv->blockedClient = NULL; 719 } else if (pPriv->target_sbc == -1 && !pPriv->blockedOnMsc) { 720 if (pPriv->blockedClient) { 721 AttendClient(pPriv->blockedClient); 722 pPriv->blockedClient = NULL; 723 } 724 } 725} 726 727void 728DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, 729 unsigned int tv_sec, unsigned int tv_usec, int type, 730 DRI2SwapEventPtr swap_complete, void *swap_data) 731{ 732 ScreenPtr pScreen = pDraw->pScreen; 733 DRI2DrawablePtr pPriv; 734 CARD64 ust = 0; 735 BoxRec box; 736 RegionRec region; 737 738 pPriv = DRI2GetDrawable(pDraw); 739 if (pPriv == NULL) { 740 xf86DrvMsg(pScreen->myNum, X_ERROR, 741 "[DRI2] %s: bad drawable\n", __func__); 742 return; 743 } 744 745 pPriv->swapsPending--; 746 pPriv->swap_count++; 747 748 box.x1 = 0; 749 box.y1 = 0; 750 box.x2 = pDraw->width; 751 box.y2 = pDraw->height; 752 RegionInit(®ion, &box, 0); 753 DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 754 DRI2BufferFrontLeft); 755 756 ust = ((CARD64)tv_sec * 1000000) + tv_usec; 757 if (swap_complete) 758 swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); 759 760 pPriv->last_swap_msc = frame; 761 pPriv->last_swap_ust = ust; 762 763 DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); 764} 765 766Bool 767DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) 768{ 769 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 770 771 /* If we're currently waiting for a swap on this drawable, reset 772 * the request and suspend the client. We only support one 773 * blocked client per drawable. */ 774 if (pPriv && 775 pPriv->swapsPending && 776 pPriv->blockedClient == NULL) { 777 ResetCurrentRequest(client); 778 client->sequence--; 779 __DRI2BlockClient(client, pPriv); 780 return TRUE; 781 } 782 783 return FALSE; 784} 785 786int 787DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 788 CARD64 divisor, CARD64 remainder, CARD64 *swap_target, 789 DRI2SwapEventPtr func, void *data) 790{ 791 ScreenPtr pScreen = pDraw->pScreen; 792 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 793 DRI2DrawablePtr pPriv; 794 DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; 795 int ret, i; 796 CARD64 ust, current_msc; 797 798 pPriv = DRI2GetDrawable(pDraw); 799 if (pPriv == NULL) { 800 xf86DrvMsg(pScreen->myNum, X_ERROR, 801 "[DRI2] %s: bad drawable\n", __func__); 802 return BadDrawable; 803 } 804 805 for (i = 0; i < pPriv->bufferCount; i++) { 806 if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft) 807 pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 808 if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft) 809 pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 810 } 811 if (pSrcBuffer == NULL || pDestBuffer == NULL) { 812 xf86DrvMsg(pScreen->myNum, X_ERROR, 813 "[DRI2] %s: drawable has no back or front?\n", __func__); 814 return BadDrawable; 815 } 816 817 /* Old DDX or no swap interval, just blit */ 818 if (!ds->ScheduleSwap || !pPriv->swap_interval) { 819 BoxRec box; 820 RegionRec region; 821 822 box.x1 = 0; 823 box.y1 = 0; 824 box.x2 = pDraw->width; 825 box.y2 = pDraw->height; 826 RegionInit(®ion, &box, 0); 827 828 pPriv->swapsPending++; 829 830 (*ds->CopyRegion)(pDraw, ®ion, pDestBuffer, pSrcBuffer); 831 DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE, 832 func, data); 833 return Success; 834 } 835 836 /* 837 * In the simple glXSwapBuffers case, all params will be 0, and we just 838 * need to schedule a swap for the last swap target + the swap interval. 839 */ 840 if (target_msc == 0 && divisor == 0 && remainder == 0) { 841 /* If the current vblank count of the drawable's crtc is lower 842 * than the count stored in last_swap_target from a previous swap 843 * then reinitialize last_swap_target to the current crtc's msc, 844 * otherwise the swap will hang. This will happen if the drawable 845 * is moved to a crtc with a lower refresh rate, or a crtc that just 846 * got enabled. 847 */ 848 if (ds->GetMSC) { 849 if (!(*ds->GetMSC)(pDraw, &ust, ¤t_msc)) 850 pPriv->last_swap_target = 0; 851 852 if (current_msc < pPriv->last_swap_target) 853 pPriv->last_swap_target = current_msc; 854 855 } 856 857 /* 858 * Swap target for this swap is last swap target + swap interval since 859 * we have to account for the current swap count, interval, and the 860 * number of pending swaps. 861 */ 862 *swap_target = pPriv->last_swap_target + pPriv->swap_interval; 863 864 } else { 865 /* glXSwapBuffersMscOML could have a 0 target_msc, honor it */ 866 *swap_target = target_msc; 867 } 868 869 pPriv->swapsPending++; 870 ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer, 871 swap_target, divisor, remainder, func, data); 872 if (!ret) { 873 pPriv->swapsPending--; /* didn't schedule */ 874 xf86DrvMsg(pScreen->myNum, X_ERROR, 875 "[DRI2] %s: driver failed to schedule swap\n", __func__); 876 return BadDrawable; 877 } 878 879 pPriv->last_swap_target = *swap_target; 880 881 /* According to spec, return expected swapbuffers count SBC after this swap 882 * will complete. 883 */ 884 *swap_target = pPriv->swap_count + pPriv->swapsPending; 885 886 DRI2InvalidateDrawable(pDraw); 887 888 return Success; 889} 890 891void 892DRI2SwapInterval(DrawablePtr pDrawable, int interval) 893{ 894 ScreenPtr pScreen = pDrawable->pScreen; 895 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 896 897 if (pPriv == NULL) { 898 xf86DrvMsg(pScreen->myNum, X_ERROR, 899 "[DRI2] %s: bad drawable\n", __func__); 900 return; 901 } 902 903 /* fixme: check against arbitrary max? */ 904 pPriv->swap_interval = interval; 905} 906 907int 908DRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc, CARD64 *sbc) 909{ 910 ScreenPtr pScreen = pDraw->pScreen; 911 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 912 DRI2DrawablePtr pPriv; 913 Bool ret; 914 915 pPriv = DRI2GetDrawable(pDraw); 916 if (pPriv == NULL) { 917 xf86DrvMsg(pScreen->myNum, X_ERROR, 918 "[DRI2] %s: bad drawable\n", __func__); 919 return BadDrawable; 920 } 921 922 if (!ds->GetMSC) { 923 *ust = 0; 924 *msc = 0; 925 *sbc = pPriv->swap_count; 926 return Success; 927 } 928 929 /* 930 * Spec needs to be updated to include unmapped or redirected 931 * drawables 932 */ 933 934 ret = (*ds->GetMSC)(pDraw, ust, msc); 935 if (!ret) 936 return BadDrawable; 937 938 *sbc = pPriv->swap_count; 939 940 return Success; 941} 942 943int 944DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 945 CARD64 divisor, CARD64 remainder) 946{ 947 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 948 DRI2DrawablePtr pPriv; 949 Bool ret; 950 951 pPriv = DRI2GetDrawable(pDraw); 952 if (pPriv == NULL) 953 return BadDrawable; 954 955 /* Old DDX just completes immediately */ 956 if (!ds->ScheduleWaitMSC) { 957 DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0); 958 959 return Success; 960 } 961 962 ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder); 963 if (!ret) 964 return BadDrawable; 965 966 return Success; 967} 968 969int 970DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc) 971{ 972 DRI2DrawablePtr pPriv; 973 974 pPriv = DRI2GetDrawable(pDraw); 975 if (pPriv == NULL) 976 return BadDrawable; 977 978 /* target_sbc == 0 means to block until all pending swaps are 979 * finished. Recalculate target_sbc to get that behaviour. 980 */ 981 if (target_sbc == 0) 982 target_sbc = pPriv->swap_count + pPriv->swapsPending; 983 984 /* If current swap count already >= target_sbc, reply and 985 * return immediately with (ust, msc, sbc) triplet of 986 * most recent completed swap. 987 */ 988 if (pPriv->swap_count >= target_sbc) { 989 ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust, 990 pPriv->last_swap_msc, pPriv->swap_count); 991 return Success; 992 } 993 994 pPriv->target_sbc = target_sbc; 995 __DRI2BlockClient(client, pPriv); 996 997 return Success; 998} 999 1000Bool 1001DRI2HasSwapControl(ScreenPtr pScreen) 1002{ 1003 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1004 1005 return ds->ScheduleSwap && ds->GetMSC; 1006} 1007 1008Bool 1009DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd, 1010 const char **driverName, const char **deviceName) 1011{ 1012 DRI2ScreenPtr ds; 1013 1014 if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 1015 return FALSE; 1016 1017 ds = DRI2GetScreen(pScreen); 1018 if (ds == NULL || driverType >= ds->numDrivers || 1019 !ds->driverNames[driverType]) 1020 return FALSE; 1021 1022 *fd = ds->fd; 1023 *driverName = ds->driverNames[driverType]; 1024 *deviceName = ds->deviceName; 1025 1026 return TRUE; 1027} 1028 1029Bool 1030DRI2Authenticate(ScreenPtr pScreen, uint32_t magic) 1031{ 1032 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1033 1034 if (ds == NULL || (*ds->AuthMagic)(ds->fd, magic)) 1035 return FALSE; 1036 1037 return TRUE; 1038} 1039 1040static int 1041DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw, 1042 WindowPtr pSib) 1043{ 1044 DrawablePtr pDraw = (DrawablePtr)pWin; 1045 ScreenPtr pScreen = pDraw->pScreen; 1046 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1047 DRI2DrawablePtr dd = DRI2GetDrawable(pDraw); 1048 int ret; 1049 1050 if (ds->ConfigNotify) { 1051 pScreen->ConfigNotify = ds->ConfigNotify; 1052 1053 ret = (*pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib); 1054 1055 ds->ConfigNotify = pScreen->ConfigNotify; 1056 pScreen->ConfigNotify = DRI2ConfigNotify; 1057 if (ret) 1058 return ret; 1059 } 1060 1061 if (!dd || (dd->width == w && dd->height == h)) 1062 return Success; 1063 1064 DRI2InvalidateDrawable(pDraw); 1065 return Success; 1066} 1067 1068Bool 1069DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) 1070{ 1071 DRI2ScreenPtr ds; 1072 const char* driverTypeNames[] = { 1073 "DRI", /* DRI2DriverDRI */ 1074 "VDPAU", /* DRI2DriverVDPAU */ 1075 }; 1076 unsigned int i; 1077 CARD8 cur_minor; 1078 1079 if (info->version < 3) 1080 return FALSE; 1081 1082 if (!xf86VGAarbiterAllowDRI(pScreen)) { 1083 xf86DrvMsg(pScreen->myNum, X_WARNING, 1084 "[DRI2] Direct rendering is not supported when VGA arb is necessary for the device\n"); 1085 return FALSE; 1086 } 1087 1088 if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 1089 return FALSE; 1090 1091 if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0)) 1092 return FALSE; 1093 1094 if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) 1095 return FALSE; 1096 1097 ds = calloc(1, sizeof *ds); 1098 if (!ds) 1099 return FALSE; 1100 1101 ds->screen = pScreen; 1102 ds->fd = info->fd; 1103 ds->deviceName = info->deviceName; 1104 dri2_major = 1; 1105 1106 ds->CreateBuffer = info->CreateBuffer; 1107 ds->DestroyBuffer = info->DestroyBuffer; 1108 ds->CopyRegion = info->CopyRegion; 1109 1110 if (info->version >= 4) { 1111 ds->ScheduleSwap = info->ScheduleSwap; 1112 ds->ScheduleWaitMSC = info->ScheduleWaitMSC; 1113 ds->GetMSC = info->GetMSC; 1114 cur_minor = 3; 1115 } else { 1116 cur_minor = 1; 1117 } 1118 1119 if (info->version >= 5) { 1120 ds->AuthMagic = info->AuthMagic; 1121 } 1122 1123 /* 1124 * if the driver doesn't provide an AuthMagic function or the info struct 1125 * version is too low, it relies on the old method (using libdrm) or fail 1126 */ 1127 if (!ds->AuthMagic) 1128#ifdef WITH_LIBDRM 1129 ds->AuthMagic = drmAuthMagic; 1130#else 1131 goto err_out; 1132#endif 1133 1134 /* Initialize minor if needed and set to minimum provied by DDX */ 1135 if (!dri2_minor || dri2_minor > cur_minor) 1136 dri2_minor = cur_minor; 1137 1138 if (info->version == 3 || info->numDrivers == 0) { 1139 /* Driver too old: use the old-style driverName field */ 1140 ds->numDrivers = 1; 1141 ds->driverNames = malloc(sizeof(*ds->driverNames)); 1142 if (!ds->driverNames) 1143 goto err_out; 1144 ds->driverNames[0] = info->driverName; 1145 } else { 1146 ds->numDrivers = info->numDrivers; 1147 ds->driverNames = malloc(info->numDrivers * sizeof(*ds->driverNames)); 1148 if (!ds->driverNames) 1149 goto err_out; 1150 memcpy(ds->driverNames, info->driverNames, 1151 info->numDrivers * sizeof(*ds->driverNames)); 1152 } 1153 1154 dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); 1155 1156 ds->ConfigNotify = pScreen->ConfigNotify; 1157 pScreen->ConfigNotify = DRI2ConfigNotify; 1158 1159 xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); 1160 for (i = 0; i < sizeof(driverTypeNames) / sizeof(driverTypeNames[0]); i++) { 1161 if (i < ds->numDrivers && ds->driverNames[i]) { 1162 xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] %s driver: %s\n", 1163 driverTypeNames[i], ds->driverNames[i]); 1164 } 1165 } 1166 1167 return TRUE; 1168 1169err_out: 1170 xf86DrvMsg(pScreen->myNum, X_WARNING, 1171 "[DRI2] Initialization failed for info version %d.\n", info->version); 1172 free(ds); 1173 return FALSE; 1174} 1175 1176void 1177DRI2CloseScreen(ScreenPtr pScreen) 1178{ 1179 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1180 1181 free(ds->driverNames); 1182 free(ds); 1183 dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL); 1184} 1185 1186extern ExtensionModule dri2ExtensionModule; 1187extern Bool DRI2ModuleSetup(void); 1188 1189/* Called by InitExtensions() */ 1190Bool 1191DRI2ModuleSetup(void) 1192{ 1193 dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable"); 1194 if (!dri2DrawableRes) 1195 return FALSE; 1196 1197 return TRUE; 1198} 1199 1200static pointer 1201DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin) 1202{ 1203 static Bool setupDone = FALSE; 1204 1205 if (!setupDone) 1206 { 1207 setupDone = TRUE; 1208 LoadExtension(&dri2ExtensionModule, FALSE); 1209 } 1210 else 1211 { 1212 if (errmaj) 1213 *errmaj = LDR_ONCEONLY; 1214 } 1215 1216 return (pointer) 1; 1217} 1218 1219static XF86ModuleVersionInfo DRI2VersRec = 1220{ 1221 "dri2", 1222 MODULEVENDORSTRING, 1223 MODINFOSTRING1, 1224 MODINFOSTRING2, 1225 XORG_VERSION_CURRENT, 1226 1, 2, 0, 1227 ABI_CLASS_EXTENSION, 1228 ABI_EXTENSION_VERSION, 1229 MOD_CLASS_NONE, 1230 { 0, 0, 0, 0 } 1231}; 1232 1233_X_EXPORT XF86ModuleData dri2ModuleData = { &DRI2VersRec, DRI2Setup, NULL }; 1234 1235void 1236DRI2Version(int *major, int *minor) 1237{ 1238 if (major != NULL) 1239 *major = DRI2VersRec.majorversion; 1240 1241 if (minor != NULL) 1242 *minor = DRI2VersRec.minorversion; 1243} 1244