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 Hgsberg (krh (at) 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 "list.h" 42 #include "scrnintstr.h" 43 #include "windowstr.h" 44 #include "dixstruct.h" 45 #include "dri2.h" 46 #include "dri2int.h" 47 #include "damage.h" 48 #include "xf86.h" 49 50 CARD8 dri2_major; /* version of DRI2 supported by DDX */ 51 CARD8 dri2_minor; 52 53 uint32_t prime_id_allocate_bitmask; 54 55 static DevPrivateKeyRec dri2ScreenPrivateKeyRec; 56 57 #define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec) 58 59 static DevPrivateKeyRec dri2WindowPrivateKeyRec; 60 61 #define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec) 62 63 static DevPrivateKeyRec dri2PixmapPrivateKeyRec; 64 65 #define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec) 66 67 static DevPrivateKeyRec dri2ClientPrivateKeyRec; 68 69 #define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec) 70 71 #define dri2ClientPrivate(_pClient) (dixLookupPrivate(&(_pClient)->devPrivates, \ 72 dri2ClientPrivateKey)) 73 74 typedef struct _DRI2Client { 75 int prime_id; 76 } DRI2ClientRec, *DRI2ClientPtr; 77 78 static RESTYPE dri2DrawableRes; 79 80 typedef struct _DRI2Screen *DRI2ScreenPtr; 81 82 typedef struct _DRI2Drawable { 83 DRI2ScreenPtr dri2_screen; 84 DrawablePtr drawable; 85 struct xorg_list reference_list; 86 int width; 87 int height; 88 DRI2BufferPtr *buffers; 89 int bufferCount; 90 unsigned int swapsPending; 91 int swap_interval; 92 CARD64 swap_count; 93 int64_t target_sbc; /* -1 means no SBC wait outstanding */ 94 CARD64 last_swap_target; /* most recently queued swap target */ 95 CARD64 last_swap_msc; /* msc at completion of most recent swap */ 96 CARD64 last_swap_ust; /* ust at completion of most recent swap */ 97 int swap_limit; /* for N-buffering */ 98 unsigned blocked[3]; 99 Bool needInvalidate; 100 int prime_id; 101 PixmapPtr prime_secondary_pixmap; 102 PixmapPtr redirectpixmap; 103 } DRI2DrawableRec, *DRI2DrawablePtr; 104 105 typedef struct _DRI2Screen { 106 ScreenPtr screen; 107 int refcnt; 108 unsigned int numDrivers; 109 const char **driverNames; 110 const char *deviceName; 111 int fd; 112 unsigned int lastSequence; 113 int prime_id; 114 115 DRI2CreateBufferProcPtr CreateBuffer; 116 DRI2DestroyBufferProcPtr DestroyBuffer; 117 DRI2CopyRegionProcPtr CopyRegion; 118 DRI2ScheduleSwapProcPtr ScheduleSwap; 119 DRI2GetMSCProcPtr GetMSC; 120 DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC; 121 DRI2AuthMagic2ProcPtr AuthMagic; 122 DRI2AuthMagicProcPtr LegacyAuthMagic; 123 DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify; 124 DRI2SwapLimitValidateProcPtr SwapLimitValidate; 125 DRI2GetParamProcPtr GetParam; 126 127 HandleExposuresProcPtr HandleExposures; 128 129 ConfigNotifyProcPtr ConfigNotify; 130 SetWindowPixmapProcPtr SetWindowPixmap; 131 DRI2CreateBuffer2ProcPtr CreateBuffer2; 132 DRI2DestroyBuffer2ProcPtr DestroyBuffer2; 133 DRI2CopyRegion2ProcPtr CopyRegion2; 134 } DRI2ScreenRec; 135 136 static void 137 destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id); 138 139 enum DRI2WakeType { 140 WAKE_SBC, 141 WAKE_MSC, 142 WAKE_SWAP, 143 }; 144 145 #define Wake(c, t) (void *)((uintptr_t)(c) | (t)) 146 147 static Bool 148 dri2WakeClient(ClientPtr client, void *closure) 149 { 150 ClientWakeup(client); 151 return TRUE; 152 } 153 154 static Bool 155 dri2WakeAll(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t) 156 { 157 int count; 158 159 if (!pPriv->blocked[t]) 160 return FALSE; 161 162 count = ClientSignalAll(client, dri2WakeClient, Wake(pPriv, t)); 163 pPriv->blocked[t] -= count; 164 return count; 165 } 166 167 static Bool 168 dri2Sleep(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t) 169 { 170 if (ClientSleep(client, dri2WakeClient, Wake(pPriv, t))) { 171 pPriv->blocked[t]++; 172 return TRUE; 173 } 174 return FALSE; 175 } 176 177 static DRI2ScreenPtr 178 DRI2GetScreen(ScreenPtr pScreen) 179 { 180 return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey); 181 } 182 183 static ScreenPtr 184 GetScreenPrime(ScreenPtr primary, int prime_id) 185 { 186 ScreenPtr secondary; 187 if (prime_id == 0) { 188 return primary; 189 } 190 xorg_list_for_each_entry(secondary, &primary->secondary_list, secondary_head) { 191 DRI2ScreenPtr ds; 192 193 if (!secondary->is_offload_secondary) 194 continue; 195 196 ds = DRI2GetScreen(secondary); 197 if (ds == NULL) 198 continue; 199 200 if (ds->prime_id == prime_id) 201 return secondary; 202 } 203 return primary; 204 } 205 206 static DRI2ScreenPtr 207 DRI2GetScreenPrime(ScreenPtr primary, int prime_id) 208 { 209 ScreenPtr secondary = GetScreenPrime(primary, prime_id); 210 return DRI2GetScreen(secondary); 211 } 212 213 static DRI2DrawablePtr 214 DRI2GetDrawable(DrawablePtr pDraw) 215 { 216 WindowPtr pWin; 217 PixmapPtr pPixmap; 218 219 switch (pDraw->type) { 220 case DRAWABLE_WINDOW: 221 pWin = (WindowPtr) pDraw; 222 return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey); 223 case DRAWABLE_PIXMAP: 224 pPixmap = (PixmapPtr) pDraw; 225 return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey); 226 default: 227 return NULL; 228 } 229 } 230 231 static DRI2DrawablePtr 232 DRI2AllocateDrawable(DrawablePtr pDraw) 233 { 234 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 235 DRI2DrawablePtr pPriv; 236 CARD64 ust; 237 WindowPtr pWin; 238 PixmapPtr pPixmap; 239 240 pPriv = malloc(sizeof *pPriv); 241 if (pPriv == NULL) 242 return NULL; 243 244 pPriv->dri2_screen = ds; 245 pPriv->drawable = pDraw; 246 pPriv->width = pDraw->width; 247 pPriv->height = pDraw->height; 248 pPriv->buffers = NULL; 249 pPriv->bufferCount = 0; 250 pPriv->swapsPending = 0; 251 pPriv->swap_count = 0; 252 pPriv->target_sbc = -1; 253 pPriv->swap_interval = 1; 254 /* Initialize last swap target from DDX if possible */ 255 if (!ds->GetMSC || !(*ds->GetMSC) (pDraw, &ust, &pPriv->last_swap_target)) 256 pPriv->last_swap_target = 0; 257 258 memset(pPriv->blocked, 0, sizeof(pPriv->blocked)); 259 pPriv->swap_limit = 1; /* default to double buffering */ 260 pPriv->last_swap_msc = 0; 261 pPriv->last_swap_ust = 0; 262 xorg_list_init(&pPriv->reference_list); 263 pPriv->needInvalidate = FALSE; 264 pPriv->redirectpixmap = NULL; 265 pPriv->prime_secondary_pixmap = NULL; 266 if (pDraw->type == DRAWABLE_WINDOW) { 267 pWin = (WindowPtr) pDraw; 268 dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv); 269 } 270 else { 271 pPixmap = (PixmapPtr) pDraw; 272 dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv); 273 } 274 275 return pPriv; 276 } 277 278 Bool 279 DRI2SwapLimit(DrawablePtr pDraw, int swap_limit) 280 { 281 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 282 DRI2ScreenPtr ds; 283 284 if (!pPriv) 285 return FALSE; 286 287 ds = pPriv->dri2_screen; 288 289 if (!ds->SwapLimitValidate || !ds->SwapLimitValidate(pDraw, swap_limit)) 290 return FALSE; 291 292 pPriv->swap_limit = swap_limit; 293 294 /* Check throttling */ 295 if (pPriv->swapsPending >= pPriv->swap_limit) 296 return TRUE; 297 298 dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP); 299 return TRUE; 300 } 301 302 typedef struct DRI2DrawableRefRec { 303 XID id; 304 XID dri2_id; 305 DRI2InvalidateProcPtr invalidate; 306 void *priv; 307 struct xorg_list link; 308 } DRI2DrawableRefRec, *DRI2DrawableRefPtr; 309 310 static DRI2DrawableRefPtr 311 DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id) 312 { 313 DRI2DrawableRefPtr ref = NULL; 314 315 xorg_list_for_each_entry(ref, &pPriv->reference_list, link) { 316 if (ref->id == id) 317 return ref; 318 } 319 320 return NULL; 321 } 322 323 static int 324 DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id, 325 DRI2InvalidateProcPtr invalidate, void *priv) 326 { 327 DRI2DrawableRefPtr ref; 328 329 ref = malloc(sizeof *ref); 330 if (ref == NULL) 331 return BadAlloc; 332 333 if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) { 334 free(ref); 335 return BadAlloc; 336 } 337 if (!DRI2LookupDrawableRef(pPriv, id)) 338 if (!AddResource(id, dri2DrawableRes, pPriv)) { 339 FreeResourceByType(dri2_id, dri2DrawableRes, TRUE); 340 free(ref); 341 return BadAlloc; 342 } 343 344 ref->id = id; 345 ref->dri2_id = dri2_id; 346 ref->invalidate = invalidate; 347 ref->priv = priv; 348 xorg_list_add(&ref->link, &pPriv->reference_list); 349 350 return Success; 351 } 352 353 int 354 DRI2CreateDrawable2(ClientPtr client, DrawablePtr pDraw, XID id, 355 DRI2InvalidateProcPtr invalidate, void *priv, 356 XID *dri2_id_out) 357 { 358 DRI2DrawablePtr pPriv; 359 DRI2ClientPtr dri2_client; 360 XID dri2_id; 361 int rc; 362 363 if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 364 return BadValue; 365 366 dri2_client = dri2ClientPrivate(client); 367 368 pPriv = DRI2GetDrawable(pDraw); 369 if (pPriv == NULL) 370 pPriv = DRI2AllocateDrawable(pDraw); 371 if (pPriv == NULL) 372 return BadAlloc; 373 374 pPriv->prime_id = dri2_client->prime_id; 375 376 dri2_id = FakeClientID(client->index); 377 rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv); 378 if (rc != Success) 379 return rc; 380 381 if (dri2_id_out) 382 *dri2_id_out = dri2_id; 383 384 return Success; 385 } 386 387 int 388 DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id, 389 DRI2InvalidateProcPtr invalidate, void *priv) 390 { 391 return DRI2CreateDrawable2(client, pDraw, id, invalidate, priv, NULL); 392 } 393 394 static int 395 DRI2DrawableGone(void *p, XID id) 396 { 397 DRI2DrawablePtr pPriv = p; 398 DRI2DrawableRefPtr ref, next; 399 WindowPtr pWin; 400 PixmapPtr pPixmap; 401 DrawablePtr pDraw; 402 int i; 403 404 xorg_list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) { 405 if (ref->dri2_id == id) { 406 xorg_list_del(&ref->link); 407 /* If this was the last ref under this X drawable XID, 408 * unregister the X drawable resource. */ 409 if (!DRI2LookupDrawableRef(pPriv, ref->id)) 410 FreeResourceByType(ref->id, dri2DrawableRes, TRUE); 411 free(ref); 412 break; 413 } 414 415 if (ref->id == id) { 416 xorg_list_del(&ref->link); 417 FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE); 418 free(ref); 419 } 420 } 421 422 if (!xorg_list_is_empty(&pPriv->reference_list)) 423 return Success; 424 425 pDraw = pPriv->drawable; 426 if (pDraw->type == DRAWABLE_WINDOW) { 427 pWin = (WindowPtr) pDraw; 428 dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL); 429 } 430 else { 431 pPixmap = (PixmapPtr) pDraw; 432 dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL); 433 } 434 435 if (pPriv->prime_secondary_pixmap) { 436 (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap); 437 (*pPriv->prime_secondary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap); 438 } 439 440 if (pPriv->buffers != NULL) { 441 for (i = 0; i < pPriv->bufferCount; i++) 442 destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id); 443 444 free(pPriv->buffers); 445 } 446 447 if (pPriv->redirectpixmap) { 448 (*pDraw->pScreen->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE); 449 (*pDraw->pScreen->DestroyPixmap)(pPriv->redirectpixmap); 450 } 451 452 dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP); 453 dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_MSC); 454 dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SBC); 455 456 free(pPriv); 457 458 return Success; 459 } 460 461 static DRI2BufferPtr 462 create_buffer(DRI2ScreenPtr ds, DrawablePtr pDraw, 463 unsigned int attachment, unsigned int format) 464 { 465 DRI2BufferPtr buffer; 466 if (ds->CreateBuffer2) 467 buffer = (*ds->CreateBuffer2)(GetScreenPrime(pDraw->pScreen, 468 DRI2GetDrawable(pDraw)->prime_id), 469 pDraw, attachment, format); 470 else 471 buffer = (*ds->CreateBuffer)(pDraw, attachment, format); 472 return buffer; 473 } 474 475 static void 476 destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id) 477 { 478 ScreenPtr primeScreen; 479 DRI2ScreenPtr ds; 480 primeScreen = GetScreenPrime(pDraw->pScreen, prime_id); 481 ds = DRI2GetScreen(primeScreen); 482 if (ds->DestroyBuffer2) 483 (*ds->DestroyBuffer2)(primeScreen, pDraw, buffer); 484 else 485 (*ds->DestroyBuffer)(pDraw, buffer); 486 } 487 488 static int 489 find_attachment(DRI2DrawablePtr pPriv, unsigned attachment) 490 { 491 int i; 492 493 if (pPriv->buffers == NULL) { 494 return -1; 495 } 496 497 for (i = 0; i < pPriv->bufferCount; i++) { 498 if ((pPriv->buffers[i] != NULL) 499 && (pPriv->buffers[i]->attachment == attachment)) { 500 return i; 501 } 502 } 503 504 return -1; 505 } 506 507 static Bool 508 allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, 509 DRI2DrawablePtr pPriv, 510 unsigned int attachment, unsigned int format, 511 int dimensions_match, DRI2BufferPtr * buffer) 512 { 513 int old_buf = find_attachment(pPriv, attachment); 514 515 if ((old_buf < 0) 516 || attachment == DRI2BufferFrontLeft 517 || !dimensions_match || (pPriv->buffers[old_buf]->format != format)) { 518 *buffer = create_buffer(ds, pDraw, attachment, format); 519 return TRUE; 520 521 } 522 else { 523 *buffer = pPriv->buffers[old_buf]; 524 525 if (ds->ReuseBufferNotify) 526 (*ds->ReuseBufferNotify) (pDraw, *buffer); 527 528 pPriv->buffers[old_buf] = NULL; 529 return FALSE; 530 } 531 } 532 533 static void 534 update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw, 535 DRI2BufferPtr * buffers, int out_count, int *width, 536 int *height) 537 { 538 int i; 539 540 if (pPriv->buffers != NULL) { 541 for (i = 0; i < pPriv->bufferCount; i++) { 542 if (pPriv->buffers[i] != NULL) { 543 destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id); 544 } 545 } 546 547 free(pPriv->buffers); 548 } 549 550 pPriv->buffers = buffers; 551 pPriv->bufferCount = out_count; 552 pPriv->width = pDraw->width; 553 pPriv->height = pDraw->height; 554 *width = pPriv->width; 555 *height = pPriv->height; 556 } 557 558 static DRI2BufferPtr * 559 do_get_buffers(DrawablePtr pDraw, int *width, int *height, 560 unsigned int *attachments, int count, int *out_count, 561 int has_format) 562 { 563 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 564 DRI2ScreenPtr ds; 565 DRI2BufferPtr *buffers; 566 unsigned attachments_bitset = 0; 567 Bool need_real_front = FALSE; 568 Bool need_fake_front = FALSE; 569 int front_format = 0; 570 int dimensions_match; 571 int buffers_changed = 0; 572 int i; 573 574 if (!pPriv || 575 count > DRI2BufferHiz + 1) { 576 *width = pDraw->width; 577 *height = pDraw->height; 578 *out_count = 0; 579 return NULL; 580 } 581 582 ds = DRI2GetScreenPrime(pDraw->pScreen, pPriv->prime_id); 583 584 dimensions_match = (pDraw->width == pPriv->width) 585 && (pDraw->height == pPriv->height); 586 587 /* Since we deduplicate attachments in the buffers array, there cannot be 588 * more entries than there are attachments. 589 */ 590 buffers = calloc((min(count, DRI2BufferHiz) + 1), sizeof(buffers[0])); 591 if (!buffers) 592 goto err_out; 593 594 for (i = 0; i < count; i++) { 595 const unsigned attachment = *(attachments++); 596 const unsigned format = (has_format) ? *(attachments++) : 0; 597 598 if (attachment > DRI2BufferHiz) 599 goto err_out; 600 601 if (attachments_bitset & (1u << attachment)) 602 continue; 603 604 attachments_bitset |= 1u << attachment; 605 606 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, 607 format, dimensions_match, &buffers[i])) 608 buffers_changed = 1; 609 610 if (buffers[i] == NULL) 611 goto err_out; 612 613 /* In certain cases the (fake) front buffer is always needed, so return 614 * it even if the client failed to request it. 615 * The logic in & after the loop accounts for the case where the client 616 * does request the (fake) front buffer, to avoid returning it multiple 617 * times. 618 */ 619 if (attachment == DRI2BufferBackLeft) { 620 need_real_front = TRUE; 621 front_format = format; 622 } 623 624 if (attachment == DRI2BufferFrontLeft) { 625 front_format = format; 626 627 if (pDraw->type == DRAWABLE_WINDOW) 628 need_fake_front = TRUE; 629 } 630 } 631 632 if (need_real_front && 633 !(attachments_bitset & (1u << DRI2BufferFrontLeft))) { 634 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft, 635 front_format, dimensions_match, 636 &buffers[i])) 637 buffers_changed = 1; 638 639 if (buffers[i] == NULL) 640 goto err_out; 641 i++; 642 } 643 644 if (need_fake_front && 645 !(attachments_bitset & (1u << DRI2BufferFakeFrontLeft))) { 646 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft, 647 front_format, dimensions_match, 648 &buffers[i])) 649 buffers_changed = 1; 650 651 if (buffers[i] == NULL) 652 goto err_out; 653 654 i++; 655 attachments_bitset |= 1u << DRI2BufferFakeFrontLeft; 656 } 657 658 *out_count = i; 659 660 update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, 661 height); 662 663 /* If the client is getting a fake front-buffer, pre-fill it with the 664 * contents of the real front-buffer. This ensures correct operation of 665 * applications that call glXWaitX before calling glDrawBuffer. 666 */ 667 if (buffers_changed && 668 (attachments_bitset & (1u << DRI2BufferFakeFrontLeft))) { 669 BoxRec box; 670 RegionRec region; 671 672 box.x1 = 0; 673 box.y1 = 0; 674 box.x2 = pPriv->width; 675 box.y2 = pPriv->height; 676 RegionInit(®ion, &box, 0); 677 678 DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 679 DRI2BufferFrontLeft); 680 } 681 682 pPriv->needInvalidate = TRUE; 683 684 return pPriv->buffers; 685 686 err_out: 687 688 *out_count = 0; 689 690 if (buffers) { 691 for (i = 0; i < count; i++) { 692 if (buffers[i] != NULL) 693 destroy_buffer(pDraw, buffers[i], 0); 694 } 695 696 free(buffers); 697 buffers = NULL; 698 } 699 700 update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, 701 height); 702 703 return buffers; 704 } 705 706 DRI2BufferPtr * 707 DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height, 708 unsigned int *attachments, int count, int *out_count) 709 { 710 return do_get_buffers(pDraw, width, height, attachments, count, 711 out_count, FALSE); 712 } 713 714 DRI2BufferPtr * 715 DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, 716 unsigned int *attachments, int count, int *out_count) 717 { 718 return do_get_buffers(pDraw, width, height, attachments, count, 719 out_count, TRUE); 720 } 721 722 static void 723 DRI2InvalidateDrawable(DrawablePtr pDraw) 724 { 725 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 726 DRI2DrawableRefPtr ref = NULL; 727 728 if (!pPriv || !pPriv->needInvalidate) 729 return; 730 731 pPriv->needInvalidate = FALSE; 732 733 xorg_list_for_each_entry(ref, &pPriv->reference_list, link) 734 ref->invalidate(pDraw, ref->priv, ref->id); 735 } 736 737 /* 738 * In the direct rendered case, we throttle the clients that have more 739 * than their share of outstanding swaps (and thus busy buffers) when a 740 * new GetBuffers request is received. In the AIGLX case, we allow the 741 * client to get the new buffers, but throttle when the next GLX request 742 * comes in (see __glXDRIcontextWait()). 743 */ 744 Bool 745 DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw) 746 { 747 DRI2DrawablePtr pPriv; 748 749 pPriv = DRI2GetDrawable(pDraw); 750 if (pPriv == NULL) 751 return FALSE; 752 753 /* Throttle to swap limit */ 754 if (pPriv->swapsPending >= pPriv->swap_limit) { 755 if (dri2Sleep(client, pPriv, WAKE_SWAP)) { 756 ResetCurrentRequest(client); 757 client->sequence--; 758 return TRUE; 759 } 760 } 761 762 return FALSE; 763 } 764 765 void 766 DRI2BlockClient(ClientPtr client, DrawablePtr pDraw) 767 { 768 DRI2DrawablePtr pPriv; 769 770 pPriv = DRI2GetDrawable(pDraw); 771 if (pPriv == NULL) 772 return; 773 774 dri2Sleep(client, pPriv, WAKE_MSC); 775 } 776 777 static inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable) 778 { 779 if (drawable->type == DRAWABLE_PIXMAP) 780 return (PixmapPtr)drawable; 781 else { 782 struct _Window *pWin = (struct _Window *)drawable; 783 return drawable->pScreen->GetWindowPixmap(pWin); 784 } 785 } 786 787 /* 788 * A TraverseTree callback to invalidate all windows using the same 789 * pixmap 790 */ 791 static int 792 DRI2InvalidateWalk(WindowPtr pWin, void *data) 793 { 794 if (pWin->drawable.pScreen->GetWindowPixmap(pWin) != data) 795 return WT_DONTWALKCHILDREN; 796 DRI2InvalidateDrawable(&pWin->drawable); 797 return WT_WALKCHILDREN; 798 } 799 800 static void 801 DRI2InvalidateDrawableAll(DrawablePtr pDraw) 802 { 803 if (pDraw->type == DRAWABLE_WINDOW) { 804 WindowPtr pWin = (WindowPtr) pDraw; 805 PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin); 806 807 /* 808 * Find the top-most window using this pixmap 809 */ 810 while (pWin->parent && 811 pDraw->pScreen->GetWindowPixmap(pWin->parent) == pPixmap) 812 pWin = pWin->parent; 813 814 /* 815 * Walk the sub-tree to invalidate all of the 816 * windows using the same pixmap 817 */ 818 TraverseTree(pWin, DRI2InvalidateWalk, pPixmap); 819 DRI2InvalidateDrawable(&pPixmap->drawable); 820 } 821 else 822 DRI2InvalidateDrawable(pDraw); 823 } 824 825 DrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest) 826 { 827 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 828 PixmapPtr spix; 829 PixmapPtr mpix = GetDrawablePixmap(pDraw); 830 ScreenPtr primary, secondary; 831 Bool ret; 832 833 primary = mpix->drawable.pScreen; 834 835 if (pDraw->type == DRAWABLE_WINDOW) { 836 WindowPtr pWin = (WindowPtr)pDraw; 837 PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin); 838 839 if (pDraw->pScreen->GetScreenPixmap(pDraw->pScreen) == pPixmap) { 840 if (pPriv->redirectpixmap && 841 pPriv->redirectpixmap->drawable.width == pDraw->width && 842 pPriv->redirectpixmap->drawable.height == pDraw->height && 843 pPriv->redirectpixmap->drawable.depth == pDraw->depth) { 844 mpix = pPriv->redirectpixmap; 845 } else { 846 if (primary->ReplaceScanoutPixmap) { 847 mpix = (*primary->CreatePixmap)(primary, pDraw->width, pDraw->height, 848 pDraw->depth, CREATE_PIXMAP_USAGE_SHARED); 849 if (!mpix) 850 return NULL; 851 852 ret = (*primary->ReplaceScanoutPixmap)(pDraw, mpix, TRUE); 853 if (ret == FALSE) { 854 (*primary->DestroyPixmap)(mpix); 855 return NULL; 856 } 857 pPriv->redirectpixmap = mpix; 858 } else 859 return NULL; 860 } 861 } else if (pPriv->redirectpixmap) { 862 (*primary->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE); 863 (*primary->DestroyPixmap)(pPriv->redirectpixmap); 864 pPriv->redirectpixmap = NULL; 865 } 866 } 867 868 secondary = GetScreenPrime(pDraw->pScreen, pPriv->prime_id); 869 870 /* check if the pixmap is still fine */ 871 if (pPriv->prime_secondary_pixmap) { 872 if (pPriv->prime_secondary_pixmap->primary_pixmap == mpix) 873 return &pPriv->prime_secondary_pixmap->drawable; 874 else { 875 PixmapUnshareSecondaryPixmap(pPriv->prime_secondary_pixmap); 876 (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap); 877 (*secondary->DestroyPixmap)(pPriv->prime_secondary_pixmap); 878 pPriv->prime_secondary_pixmap = NULL; 879 } 880 } 881 882 spix = PixmapShareToSecondary(mpix, secondary); 883 if (!spix) 884 return NULL; 885 886 pPriv->prime_secondary_pixmap = spix; 887 #ifdef COMPOSITE 888 spix->screen_x = mpix->screen_x; 889 spix->screen_y = mpix->screen_y; 890 #endif 891 892 DRI2InvalidateDrawableAll(pDraw); 893 return &spix->drawable; 894 } 895 896 static void dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, 897 DRI2BufferPtr pDest, DRI2BufferPtr pSrc) 898 { 899 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 900 DRI2ScreenPtr ds; 901 ScreenPtr primeScreen; 902 903 primeScreen = GetScreenPrime(pDraw->pScreen, pPriv->prime_id); 904 ds = DRI2GetScreen(primeScreen); 905 906 if (ds->CopyRegion2) 907 (*ds->CopyRegion2)(primeScreen, pDraw, pRegion, pDest, pSrc); 908 else 909 (*ds->CopyRegion) (pDraw, pRegion, pDest, pSrc); 910 911 /* cause damage to the box */ 912 if (pPriv->prime_id) { 913 BoxRec box; 914 RegionRec region; 915 box.x1 = 0; 916 box.x2 = box.x1 + pDraw->width; 917 box.y1 = 0; 918 box.y2 = box.y1 + pDraw->height; 919 RegionInit(®ion, &box, 1); 920 RegionTranslate(®ion, pDraw->x, pDraw->y); 921 DamageRegionAppend(pDraw, ®ion); 922 DamageRegionProcessPending(pDraw); 923 RegionUninit(®ion); 924 } 925 } 926 927 int 928 DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, 929 unsigned int dest, unsigned int src) 930 { 931 DRI2DrawablePtr pPriv; 932 DRI2BufferPtr pDestBuffer, pSrcBuffer; 933 int i; 934 935 pPriv = DRI2GetDrawable(pDraw); 936 if (pPriv == NULL) 937 return BadDrawable; 938 939 pDestBuffer = NULL; 940 pSrcBuffer = NULL; 941 for (i = 0; i < pPriv->bufferCount; i++) { 942 if (pPriv->buffers[i]->attachment == dest) 943 pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 944 if (pPriv->buffers[i]->attachment == src) 945 pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 946 } 947 if (pSrcBuffer == NULL || pDestBuffer == NULL) 948 return BadValue; 949 950 dri2_copy_region(pDraw, pRegion, pDestBuffer, pSrcBuffer); 951 952 return Success; 953 } 954 955 /* Can this drawable be page flipped? */ 956 Bool 957 DRI2CanFlip(DrawablePtr pDraw) 958 { 959 ScreenPtr pScreen = pDraw->pScreen; 960 WindowPtr pWin, pRoot; 961 PixmapPtr pWinPixmap, pRootPixmap; 962 963 if (pDraw->type == DRAWABLE_PIXMAP) 964 return TRUE; 965 966 pRoot = pScreen->root; 967 pRootPixmap = pScreen->GetWindowPixmap(pRoot); 968 969 pWin = (WindowPtr) pDraw; 970 pWinPixmap = pScreen->GetWindowPixmap(pWin); 971 if (pRootPixmap != pWinPixmap) 972 return FALSE; 973 if (!RegionEqual(&pWin->clipList, &pRoot->winSize)) 974 return FALSE; 975 976 /* Does the window match the pixmap exactly? */ 977 if (pDraw->x != 0 || pDraw->y != 0 || 978 #ifdef COMPOSITE 979 pDraw->x != pWinPixmap->screen_x || pDraw->y != pWinPixmap->screen_y || 980 #endif 981 pDraw->width != pWinPixmap->drawable.width || 982 pDraw->height != pWinPixmap->drawable.height) 983 return FALSE; 984 985 return TRUE; 986 } 987 988 /* Can we do a pixmap exchange instead of a blit? */ 989 Bool 990 DRI2CanExchange(DrawablePtr pDraw) 991 { 992 return FALSE; 993 } 994 995 void 996 DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, 997 unsigned int tv_sec, unsigned int tv_usec) 998 { 999 DRI2DrawablePtr pPriv; 1000 1001 pPriv = DRI2GetDrawable(pDraw); 1002 if (pPriv == NULL) 1003 return; 1004 1005 ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec, 1006 frame, pPriv->swap_count); 1007 1008 dri2WakeAll(client, pPriv, WAKE_MSC); 1009 } 1010 1011 static void 1012 DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame, 1013 unsigned int tv_sec, unsigned int tv_usec) 1014 { 1015 ScreenPtr pScreen = pDraw->pScreen; 1016 DRI2DrawablePtr pPriv; 1017 1018 pPriv = DRI2GetDrawable(pDraw); 1019 if (pPriv == NULL) { 1020 xf86DrvMsg(pScreen->myNum, X_ERROR, 1021 "[DRI2] %s: bad drawable\n", __func__); 1022 return; 1023 } 1024 1025 /* 1026 * Swap completed. 1027 * Wake the client iff: 1028 * - it was waiting on SBC 1029 * - was blocked due to GLX make current 1030 * - was blocked due to swap throttling 1031 * - is not blocked due to an MSC wait 1032 */ 1033 if (pPriv->target_sbc != -1 && pPriv->target_sbc <= pPriv->swap_count) { 1034 if (dri2WakeAll(client, pPriv, WAKE_SBC)) { 1035 ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec, 1036 frame, pPriv->swap_count); 1037 pPriv->target_sbc = -1; 1038 } 1039 } 1040 1041 dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP); 1042 } 1043 1044 void 1045 DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, 1046 unsigned int tv_sec, unsigned int tv_usec, int type, 1047 DRI2SwapEventPtr swap_complete, void *swap_data) 1048 { 1049 ScreenPtr pScreen = pDraw->pScreen; 1050 DRI2DrawablePtr pPriv; 1051 CARD64 ust = 0; 1052 BoxRec box; 1053 RegionRec region; 1054 1055 pPriv = DRI2GetDrawable(pDraw); 1056 if (pPriv == NULL) { 1057 xf86DrvMsg(pScreen->myNum, X_ERROR, 1058 "[DRI2] %s: bad drawable\n", __func__); 1059 return; 1060 } 1061 1062 pPriv->swapsPending--; 1063 pPriv->swap_count++; 1064 1065 box.x1 = 0; 1066 box.y1 = 0; 1067 box.x2 = pDraw->width; 1068 box.y2 = pDraw->height; 1069 RegionInit(®ion, &box, 0); 1070 DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 1071 DRI2BufferFrontLeft); 1072 1073 ust = ((CARD64) tv_sec * 1000000) + tv_usec; 1074 if (swap_complete) 1075 swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); 1076 1077 pPriv->last_swap_msc = frame; 1078 pPriv->last_swap_ust = ust; 1079 1080 DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); 1081 } 1082 1083 Bool 1084 DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) 1085 { 1086 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 1087 1088 /* If we're currently waiting for a swap on this drawable, reset 1089 * the request and suspend the client. */ 1090 if (pPriv && pPriv->swapsPending) { 1091 if (dri2Sleep(client, pPriv, WAKE_SWAP)) { 1092 ResetCurrentRequest(client); 1093 client->sequence--; 1094 return TRUE; 1095 } 1096 } 1097 1098 return FALSE; 1099 } 1100 1101 1102 1103 int 1104 DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 1105 CARD64 divisor, CARD64 remainder, CARD64 * swap_target, 1106 DRI2SwapEventPtr func, void *data) 1107 { 1108 ScreenPtr pScreen = pDraw->pScreen; 1109 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 1110 DRI2DrawablePtr pPriv; 1111 DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; 1112 int ret, i; 1113 CARD64 ust, current_msc; 1114 1115 pPriv = DRI2GetDrawable(pDraw); 1116 if (pPriv == NULL) { 1117 xf86DrvMsg(pScreen->myNum, X_ERROR, 1118 "[DRI2] %s: bad drawable\n", __func__); 1119 return BadDrawable; 1120 } 1121 1122 /* According to spec, return expected swapbuffers count SBC after this swap 1123 * will complete. This is ignored unless we return Success, but it must be 1124 * initialized on every path where we return Success or the caller will send 1125 * an uninitialized value off the stack to the client. So let's initialize 1126 * it as early as possible, just to be sure. 1127 */ 1128 *swap_target = pPriv->swap_count + pPriv->swapsPending + 1; 1129 1130 for (i = 0; i < pPriv->bufferCount; i++) { 1131 if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft) 1132 pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 1133 if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft) 1134 pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 1135 } 1136 if (pSrcBuffer == NULL || pDestBuffer == NULL) { 1137 xf86DrvMsg(pScreen->myNum, X_ERROR, 1138 "[DRI2] %s: drawable has no back or front?\n", __func__); 1139 return BadDrawable; 1140 } 1141 1142 /* Old DDX or no swap interval, just blit */ 1143 if (!ds->ScheduleSwap || !pPriv->swap_interval || pPriv->prime_id) { 1144 BoxRec box; 1145 RegionRec region; 1146 1147 box.x1 = 0; 1148 box.y1 = 0; 1149 box.x2 = pDraw->width; 1150 box.y2 = pDraw->height; 1151 RegionInit(®ion, &box, 0); 1152 1153 pPriv->swapsPending++; 1154 1155 dri2_copy_region(pDraw, ®ion, pDestBuffer, pSrcBuffer); 1156 DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE, 1157 func, data); 1158 return Success; 1159 } 1160 1161 /* 1162 * In the simple glXSwapBuffers case, all params will be 0, and we just 1163 * need to schedule a swap for the last swap target + the swap interval. 1164 */ 1165 if (target_msc == 0 && divisor == 0 && remainder == 0) { 1166 /* If the current vblank count of the drawable's crtc is lower 1167 * than the count stored in last_swap_target from a previous swap 1168 * then reinitialize last_swap_target to the current crtc's msc, 1169 * otherwise the swap will hang. This will happen if the drawable 1170 * is moved to a crtc with a lower refresh rate, or a crtc that just 1171 * got enabled. 1172 */ 1173 if (ds->GetMSC) { 1174 if (!(*ds->GetMSC) (pDraw, &ust, ¤t_msc)) 1175 pPriv->last_swap_target = 0; 1176 1177 if (current_msc < pPriv->last_swap_target) 1178 pPriv->last_swap_target = current_msc; 1179 1180 } 1181 1182 /* 1183 * Swap target for this swap is last swap target + swap interval since 1184 * we have to account for the current swap count, interval, and the 1185 * number of pending swaps. 1186 */ 1187 target_msc = pPriv->last_swap_target + pPriv->swap_interval; 1188 1189 } 1190 1191 pPriv->swapsPending++; 1192 ret = (*ds->ScheduleSwap) (client, pDraw, pDestBuffer, pSrcBuffer, 1193 &target_msc, divisor, remainder, func, data); 1194 if (!ret) { 1195 pPriv->swapsPending--; /* didn't schedule */ 1196 xf86DrvMsg(pScreen->myNum, X_ERROR, 1197 "[DRI2] %s: driver failed to schedule swap\n", __func__); 1198 return BadDrawable; 1199 } 1200 1201 pPriv->last_swap_target = target_msc; 1202 1203 DRI2InvalidateDrawableAll(pDraw); 1204 1205 return Success; 1206 } 1207 1208 void 1209 DRI2SwapInterval(DrawablePtr pDrawable, int interval) 1210 { 1211 ScreenPtr pScreen = pDrawable->pScreen; 1212 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 1213 1214 if (pPriv == NULL) { 1215 xf86DrvMsg(pScreen->myNum, X_ERROR, 1216 "[DRI2] %s: bad drawable\n", __func__); 1217 return; 1218 } 1219 1220 /* fixme: check against arbitrary max? */ 1221 pPriv->swap_interval = interval; 1222 } 1223 1224 int 1225 DRI2GetMSC(DrawablePtr pDraw, CARD64 * ust, CARD64 * msc, CARD64 * sbc) 1226 { 1227 ScreenPtr pScreen = pDraw->pScreen; 1228 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 1229 DRI2DrawablePtr pPriv; 1230 Bool ret; 1231 1232 pPriv = DRI2GetDrawable(pDraw); 1233 if (pPriv == NULL) { 1234 xf86DrvMsg(pScreen->myNum, X_ERROR, 1235 "[DRI2] %s: bad drawable\n", __func__); 1236 return BadDrawable; 1237 } 1238 1239 if (!ds->GetMSC) { 1240 *ust = 0; 1241 *msc = 0; 1242 *sbc = pPriv->swap_count; 1243 return Success; 1244 } 1245 1246 /* 1247 * Spec needs to be updated to include unmapped or redirected 1248 * drawables 1249 */ 1250 1251 ret = (*ds->GetMSC) (pDraw, ust, msc); 1252 if (!ret) 1253 return BadDrawable; 1254 1255 *sbc = pPriv->swap_count; 1256 1257 return Success; 1258 } 1259 1260 int 1261 DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 1262 CARD64 divisor, CARD64 remainder) 1263 { 1264 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 1265 DRI2DrawablePtr pPriv; 1266 Bool ret; 1267 1268 pPriv = DRI2GetDrawable(pDraw); 1269 if (pPriv == NULL) 1270 return BadDrawable; 1271 1272 /* Old DDX just completes immediately */ 1273 if (!ds->ScheduleWaitMSC) { 1274 DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0); 1275 1276 return Success; 1277 } 1278 1279 ret = 1280 (*ds->ScheduleWaitMSC) (client, pDraw, target_msc, divisor, remainder); 1281 if (!ret) 1282 return BadDrawable; 1283 1284 return Success; 1285 } 1286 1287 int 1288 DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc) 1289 { 1290 DRI2DrawablePtr pPriv; 1291 1292 pPriv = DRI2GetDrawable(pDraw); 1293 if (pPriv == NULL) 1294 return BadDrawable; 1295 1296 if (pPriv->target_sbc != -1) /* already in use */ 1297 return BadDrawable; 1298 1299 /* target_sbc == 0 means to block until all pending swaps are 1300 * finished. Recalculate target_sbc to get that behaviour. 1301 */ 1302 if (target_sbc == 0) 1303 target_sbc = pPriv->swap_count + pPriv->swapsPending; 1304 1305 /* If current swap count already >= target_sbc, reply and 1306 * return immediately with (ust, msc, sbc) triplet of 1307 * most recent completed swap. 1308 */ 1309 if (pPriv->swap_count >= target_sbc) { 1310 ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust, 1311 pPriv->last_swap_msc, pPriv->swap_count); 1312 return Success; 1313 } 1314 1315 if (!dri2Sleep(client, pPriv, WAKE_SBC)) 1316 return BadAlloc; 1317 1318 pPriv->target_sbc = target_sbc; 1319 return Success; 1320 } 1321 1322 Bool 1323 DRI2HasSwapControl(ScreenPtr pScreen) 1324 { 1325 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1326 1327 return ds->ScheduleSwap && ds->GetMSC; 1328 } 1329 1330 Bool 1331 DRI2Connect(ClientPtr client, ScreenPtr pScreen, 1332 unsigned int driverType, int *fd, 1333 const char **driverName, const char **deviceName) 1334 { 1335 DRI2ScreenPtr ds; 1336 uint32_t prime_id = DRI2DriverPrimeId(driverType); 1337 uint32_t driver_id = driverType & 0xffff; 1338 1339 if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 1340 return FALSE; 1341 1342 ds = DRI2GetScreenPrime(pScreen, prime_id); 1343 if (ds == NULL) 1344 return FALSE; 1345 1346 if (driver_id >= ds->numDrivers || 1347 !ds->driverNames[driver_id]) 1348 return FALSE; 1349 1350 *driverName = ds->driverNames[driver_id]; 1351 *deviceName = ds->deviceName; 1352 *fd = ds->fd; 1353 1354 if (client) { 1355 DRI2ClientPtr dri2_client; 1356 dri2_client = dri2ClientPrivate(client); 1357 dri2_client->prime_id = prime_id; 1358 } 1359 1360 return TRUE; 1361 } 1362 1363 static int 1364 DRI2AuthMagic (ScreenPtr pScreen, uint32_t magic) 1365 { 1366 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1367 if (ds == NULL) 1368 return -EINVAL; 1369 1370 return (*ds->LegacyAuthMagic) (ds->fd, magic); 1371 } 1372 1373 Bool 1374 DRI2Authenticate(ClientPtr client, ScreenPtr pScreen, uint32_t magic) 1375 { 1376 DRI2ScreenPtr ds; 1377 DRI2ClientPtr dri2_client; 1378 ScreenPtr primescreen; 1379 1380 if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 1381 return FALSE; 1382 1383 dri2_client = dri2ClientPrivate(client); 1384 1385 ds = DRI2GetScreenPrime(pScreen, dri2_client->prime_id); 1386 if (ds == NULL) 1387 return FALSE; 1388 1389 primescreen = GetScreenPrime(pScreen, dri2_client->prime_id); 1390 if ((*ds->AuthMagic)(primescreen, magic)) 1391 return FALSE; 1392 return TRUE; 1393 } 1394 1395 static int 1396 DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw, 1397 WindowPtr pSib) 1398 { 1399 DrawablePtr pDraw = (DrawablePtr) pWin; 1400 ScreenPtr pScreen = pDraw->pScreen; 1401 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1402 DRI2DrawablePtr dd = DRI2GetDrawable(pDraw); 1403 int ret; 1404 1405 if (ds->ConfigNotify) { 1406 pScreen->ConfigNotify = ds->ConfigNotify; 1407 1408 ret = (*pScreen->ConfigNotify) (pWin, x, y, w, h, bw, pSib); 1409 1410 ds->ConfigNotify = pScreen->ConfigNotify; 1411 pScreen->ConfigNotify = DRI2ConfigNotify; 1412 if (ret) 1413 return ret; 1414 } 1415 1416 if (!dd || (dd->width == w && dd->height == h)) 1417 return Success; 1418 1419 DRI2InvalidateDrawable(pDraw); 1420 return Success; 1421 } 1422 1423 static void 1424 DRI2SetWindowPixmap(WindowPtr pWin, PixmapPtr pPix) 1425 { 1426 ScreenPtr pScreen = pWin->drawable.pScreen; 1427 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1428 1429 pScreen->SetWindowPixmap = ds->SetWindowPixmap; 1430 (*pScreen->SetWindowPixmap) (pWin, pPix); 1431 ds->SetWindowPixmap = pScreen->SetWindowPixmap; 1432 pScreen->SetWindowPixmap = DRI2SetWindowPixmap; 1433 1434 DRI2InvalidateDrawable(&pWin->drawable); 1435 } 1436 1437 #define MAX_PRIME DRI2DriverPrimeMask 1438 static int 1439 get_prime_id(void) 1440 { 1441 int i; 1442 /* start at 1, prime id 0 is just normal driver */ 1443 for (i = 1; i < MAX_PRIME; i++) { 1444 if (prime_id_allocate_bitmask & (1 << i)) 1445 continue; 1446 1447 prime_id_allocate_bitmask |= (1 << i); 1448 return i; 1449 } 1450 return -1; 1451 } 1452 1453 #include "pci_ids/pci_id_driver_map.h" 1454 1455 static char * 1456 dri2_probe_driver_name(ScreenPtr pScreen, DRI2InfoPtr info) 1457 { 1458 #ifdef WITH_LIBDRM 1459 int i, j; 1460 char *driver = NULL; 1461 drmDevicePtr dev; 1462 1463 /* For non-PCI devices and drmGetDevice fail, just assume that 1464 * the 3D driver is named the same as the kernel driver. This is 1465 * currently true for vc4 and msm (freedreno). 1466 */ 1467 if (drmGetDevice(info->fd, &dev) || dev->bustype != DRM_BUS_PCI) { 1468 drmVersionPtr version = drmGetVersion(info->fd); 1469 1470 if (!version) { 1471 xf86DrvMsg(pScreen->myNum, X_ERROR, 1472 "[DRI2] Couldn't drmGetVersion() on non-PCI device, " 1473 "no driver name found.\n"); 1474 return NULL; 1475 } 1476 1477 driver = strndup(version->name, version->name_len); 1478 drmFreeVersion(version); 1479 return driver; 1480 } 1481 1482 for (i = 0; driver_map[i].driver; i++) { 1483 if (dev->deviceinfo.pci->vendor_id != driver_map[i].vendor_id) 1484 continue; 1485 1486 if (driver_map[i].num_chips_ids == -1) { 1487 driver = strdup(driver_map[i].driver); 1488 goto out; 1489 } 1490 1491 for (j = 0; j < driver_map[i].num_chips_ids; j++) { 1492 if (driver_map[i].chip_ids[j] == dev->deviceinfo.pci->device_id) { 1493 driver = strdup(driver_map[i].driver); 1494 goto out; 1495 } 1496 } 1497 } 1498 1499 xf86DrvMsg(pScreen->myNum, X_ERROR, 1500 "[DRI2] No driver mapping found for PCI device " 1501 "0x%04x / 0x%04x\n", 1502 dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id); 1503 out: 1504 drmFreeDevice(&dev); 1505 return driver; 1506 #else 1507 return NULL; 1508 #endif 1509 } 1510 1511 Bool 1512 DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) 1513 { 1514 DRI2ScreenPtr ds; 1515 1516 const char *driverTypeNames[] = { 1517 "DRI", /* DRI2DriverDRI */ 1518 "VDPAU", /* DRI2DriverVDPAU */ 1519 }; 1520 unsigned int i; 1521 CARD8 cur_minor; 1522 1523 if (info->version < 3) 1524 return FALSE; 1525 1526 if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 1527 return FALSE; 1528 1529 if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0)) 1530 return FALSE; 1531 1532 if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) 1533 return FALSE; 1534 1535 if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DRI2ClientRec))) 1536 return FALSE; 1537 1538 ds = calloc(1, sizeof *ds); 1539 if (!ds) 1540 return FALSE; 1541 1542 ds->screen = pScreen; 1543 ds->fd = info->fd; 1544 ds->deviceName = info->deviceName; 1545 dri2_major = 1; 1546 1547 ds->CreateBuffer = info->CreateBuffer; 1548 ds->DestroyBuffer = info->DestroyBuffer; 1549 ds->CopyRegion = info->CopyRegion; 1550 cur_minor = 1; 1551 1552 if (info->version >= 4) { 1553 ds->ScheduleSwap = info->ScheduleSwap; 1554 ds->ScheduleWaitMSC = info->ScheduleWaitMSC; 1555 ds->GetMSC = info->GetMSC; 1556 cur_minor = 3; 1557 } 1558 1559 if (info->version >= 5) { 1560 ds->LegacyAuthMagic = info->AuthMagic; 1561 } 1562 1563 if (info->version >= 6) { 1564 ds->ReuseBufferNotify = info->ReuseBufferNotify; 1565 ds->SwapLimitValidate = info->SwapLimitValidate; 1566 } 1567 1568 if (info->version >= 7) { 1569 ds->GetParam = info->GetParam; 1570 cur_minor = 4; 1571 } 1572 1573 if (info->version >= 8) { 1574 ds->AuthMagic = info->AuthMagic2; 1575 } 1576 1577 if (info->version >= 9) { 1578 ds->CreateBuffer2 = info->CreateBuffer2; 1579 if (info->CreateBuffer2 && pScreen->isGPU) { 1580 ds->prime_id = get_prime_id(); 1581 if (ds->prime_id == -1) { 1582 free(ds); 1583 return FALSE; 1584 } 1585 } 1586 ds->DestroyBuffer2 = info->DestroyBuffer2; 1587 ds->CopyRegion2 = info->CopyRegion2; 1588 } 1589 1590 /* 1591 * if the driver doesn't provide an AuthMagic function or the info struct 1592 * version is too low, call through LegacyAuthMagic 1593 */ 1594 if (!ds->AuthMagic) { 1595 ds->AuthMagic = DRI2AuthMagic; 1596 /* 1597 * If the driver doesn't provide an AuthMagic function 1598 * it relies on the old method (using libdrm) or fails 1599 */ 1600 if (!ds->LegacyAuthMagic) 1601 #ifdef WITH_LIBDRM 1602 ds->LegacyAuthMagic = drmAuthMagic; 1603 #else 1604 goto err_out; 1605 #endif 1606 } 1607 1608 /* Initialize minor if needed and set to minimum provied by DDX */ 1609 if (!dri2_minor || dri2_minor > cur_minor) 1610 dri2_minor = cur_minor; 1611 1612 if (info->version == 3 || info->numDrivers == 0) { 1613 /* Driver too old: use the old-style driverName field */ 1614 ds->numDrivers = info->driverName ? 1 : 2; 1615 ds->driverNames = xallocarray(ds->numDrivers, sizeof(*ds->driverNames)); 1616 if (!ds->driverNames) 1617 goto err_out; 1618 1619 if (info->driverName) { 1620 ds->driverNames[0] = info->driverName; 1621 } else { 1622 /* FIXME dri2_probe_driver_name() returns a strdup-ed string, 1623 * currently this gets leaked */ 1624 ds->driverNames[0] = ds->driverNames[1] = dri2_probe_driver_name(pScreen, info); 1625 if (!ds->driverNames[0]) 1626 return FALSE; 1627 1628 /* There is no VDPAU driver for i965, fallback to the generic 1629 * OpenGL/VAAPI va_gl backend to emulate VDPAU on i965. */ 1630 if (strcmp(ds->driverNames[0], "i965") == 0) 1631 ds->driverNames[1] = "va_gl"; 1632 } 1633 } 1634 else { 1635 ds->numDrivers = info->numDrivers; 1636 ds->driverNames = xallocarray(info->numDrivers, sizeof(*ds->driverNames)); 1637 if (!ds->driverNames) 1638 goto err_out; 1639 memcpy(ds->driverNames, info->driverNames, 1640 info->numDrivers * sizeof(*ds->driverNames)); 1641 } 1642 1643 dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); 1644 1645 ds->ConfigNotify = pScreen->ConfigNotify; 1646 pScreen->ConfigNotify = DRI2ConfigNotify; 1647 1648 ds->SetWindowPixmap = pScreen->SetWindowPixmap; 1649 pScreen->SetWindowPixmap = DRI2SetWindowPixmap; 1650 1651 xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); 1652 for (i = 0; i < ARRAY_SIZE(driverTypeNames); i++) { 1653 if (i < ds->numDrivers && ds->driverNames[i]) { 1654 xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] %s driver: %s\n", 1655 driverTypeNames[i], ds->driverNames[i]); 1656 } 1657 } 1658 1659 return TRUE; 1660 1661 err_out: 1662 xf86DrvMsg(pScreen->myNum, X_WARNING, 1663 "[DRI2] Initialization failed for info version %d.\n", 1664 info->version); 1665 free(ds); 1666 return FALSE; 1667 } 1668 1669 void 1670 DRI2CloseScreen(ScreenPtr pScreen) 1671 { 1672 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1673 1674 pScreen->ConfigNotify = ds->ConfigNotify; 1675 pScreen->SetWindowPixmap = ds->SetWindowPixmap; 1676 1677 if (ds->prime_id) 1678 prime_id_allocate_bitmask &= ~(1 << ds->prime_id); 1679 free(ds->driverNames); 1680 free(ds); 1681 dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL); 1682 } 1683 1684 /* Called by InitExtensions() */ 1685 Bool 1686 DRI2ModuleSetup(void) 1687 { 1688 dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable"); 1689 if (!dri2DrawableRes) 1690 return FALSE; 1691 1692 return TRUE; 1693 } 1694 1695 void 1696 DRI2Version(int *major, int *minor) 1697 { 1698 if (major != NULL) 1699 *major = 1; 1700 1701 if (minor != NULL) 1702 *minor = 2; 1703 } 1704 1705 int 1706 DRI2GetParam(ClientPtr client, 1707 DrawablePtr drawable, 1708 CARD64 param, 1709 BOOL *is_param_recognized, 1710 CARD64 *value) 1711 { 1712 DRI2ScreenPtr ds = DRI2GetScreen(drawable->pScreen); 1713 char high_byte = (param >> 24); 1714 1715 switch (high_byte) { 1716 case 0: 1717 /* Parameter names whose high_byte is 0 are reserved for the X 1718 * server. The server currently recognizes no parameters. 1719 */ 1720 goto not_recognized; 1721 case 1: 1722 /* Parameter names whose high byte is 1 are reserved for the DDX. */ 1723 if (ds->GetParam) 1724 return ds->GetParam(client, drawable, param, 1725 is_param_recognized, value); 1726 else 1727 goto not_recognized; 1728 default: 1729 /* Other parameter names are reserved for future use. They are never 1730 * recognized. 1731 */ 1732 goto not_recognized; 1733 } 1734 1735 not_recognized: 1736 *is_param_recognized = FALSE; 1737 return Success; 1738 } 1739