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