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