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