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