dri2.c revision 8223e2f2
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 "xf86VGAarbiter.h" 48 49#include "xf86.h" 50 51CARD8 dri2_major; /* version of DRI2 supported by DDX */ 52CARD8 dri2_minor; 53 54static DevPrivateKeyRec dri2ScreenPrivateKeyRec; 55#define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec) 56 57static DevPrivateKeyRec dri2WindowPrivateKeyRec; 58#define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec) 59 60static DevPrivateKeyRec dri2PixmapPrivateKeyRec; 61#define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec) 62 63static RESTYPE dri2DrawableRes; 64 65typedef struct _DRI2Screen *DRI2ScreenPtr; 66 67typedef struct _DRI2Drawable { 68 DRI2ScreenPtr dri2_screen; 69 DrawablePtr drawable; 70 struct list reference_list; 71 int width; 72 int height; 73 DRI2BufferPtr *buffers; 74 int bufferCount; 75 unsigned int swapsPending; 76 ClientPtr blockedClient; 77 Bool blockedOnMsc; 78 int swap_interval; 79 CARD64 swap_count; 80 int64_t target_sbc; /* -1 means no SBC wait outstanding */ 81 CARD64 last_swap_target; /* most recently queued swap target */ 82 CARD64 last_swap_msc; /* msc at completion of most recent swap */ 83 CARD64 last_swap_ust; /* ust at completion of most recent swap */ 84 int swap_limit; /* for N-buffering */ 85 unsigned long serialNumber; 86} DRI2DrawableRec, *DRI2DrawablePtr; 87 88typedef struct _DRI2Screen { 89 ScreenPtr screen; 90 int refcnt; 91 unsigned int numDrivers; 92 const char **driverNames; 93 const char *deviceName; 94 int fd; 95 unsigned int lastSequence; 96 97 DRI2CreateBufferProcPtr CreateBuffer; 98 DRI2DestroyBufferProcPtr DestroyBuffer; 99 DRI2CopyRegionProcPtr CopyRegion; 100 DRI2ScheduleSwapProcPtr ScheduleSwap; 101 DRI2GetMSCProcPtr GetMSC; 102 DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC; 103 DRI2AuthMagicProcPtr AuthMagic; 104 105 HandleExposuresProcPtr HandleExposures; 106 107 ConfigNotifyProcPtr ConfigNotify; 108} DRI2ScreenRec; 109 110static DRI2ScreenPtr 111DRI2GetScreen(ScreenPtr pScreen) 112{ 113 return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey); 114} 115 116static DRI2DrawablePtr 117DRI2GetDrawable(DrawablePtr pDraw) 118{ 119 WindowPtr pWin; 120 PixmapPtr pPixmap; 121 122 switch (pDraw->type) { 123 case DRAWABLE_WINDOW: 124 pWin = (WindowPtr) pDraw; 125 return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey); 126 case DRAWABLE_PIXMAP: 127 pPixmap = (PixmapPtr) pDraw; 128 return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey); 129 default: 130 return NULL; 131 } 132} 133 134static unsigned long 135DRI2DrawableSerial(DrawablePtr pDraw) 136{ 137 ScreenPtr pScreen = pDraw->pScreen; 138 PixmapPtr pPix; 139 140 if (pDraw->type != DRAWABLE_WINDOW) 141 return pDraw->serialNumber; 142 143 pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw); 144 return pPix->drawable.serialNumber; 145} 146 147static DRI2DrawablePtr 148DRI2AllocateDrawable(DrawablePtr pDraw) 149{ 150 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 151 DRI2DrawablePtr pPriv; 152 CARD64 ust; 153 WindowPtr pWin; 154 PixmapPtr pPixmap; 155 156 pPriv = malloc(sizeof *pPriv); 157 if (pPriv == NULL) 158 return NULL; 159 160 pPriv->dri2_screen = ds; 161 pPriv->drawable = pDraw; 162 pPriv->width = pDraw->width; 163 pPriv->height = pDraw->height; 164 pPriv->buffers = NULL; 165 pPriv->bufferCount = 0; 166 pPriv->swapsPending = 0; 167 pPriv->blockedClient = NULL; 168 pPriv->blockedOnMsc = FALSE; 169 pPriv->swap_count = 0; 170 pPriv->target_sbc = -1; 171 pPriv->swap_interval = 1; 172 /* Initialize last swap target from DDX if possible */ 173 if (!ds->GetMSC || !(*ds->GetMSC)(pDraw, &ust, &pPriv->last_swap_target)) 174 pPriv->last_swap_target = 0; 175 176 pPriv->swap_limit = 1; /* default to double buffering */ 177 pPriv->last_swap_msc = 0; 178 pPriv->last_swap_ust = 0; 179 list_init(&pPriv->reference_list); 180 pPriv->serialNumber = DRI2DrawableSerial(pDraw); 181 182 if (pDraw->type == DRAWABLE_WINDOW) { 183 pWin = (WindowPtr) pDraw; 184 dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv); 185 } else { 186 pPixmap = (PixmapPtr) pDraw; 187 dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv); 188 } 189 190 return pPriv; 191} 192 193typedef struct DRI2DrawableRefRec { 194 XID id; 195 XID dri2_id; 196 DRI2InvalidateProcPtr invalidate; 197 void *priv; 198 struct list link; 199} DRI2DrawableRefRec, *DRI2DrawableRefPtr; 200 201static DRI2DrawableRefPtr 202DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id) 203{ 204 DRI2DrawableRefPtr ref; 205 206 list_for_each_entry(ref, &pPriv->reference_list, link) { 207 if (ref->id == id) 208 return ref; 209 } 210 211 return NULL; 212} 213 214static int 215DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id, 216 DRI2InvalidateProcPtr invalidate, void *priv) 217{ 218 DRI2DrawableRefPtr ref; 219 220 ref = malloc(sizeof *ref); 221 if (ref == NULL) 222 return BadAlloc; 223 224 if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) 225 return BadAlloc; 226 if (!DRI2LookupDrawableRef(pPriv, id)) 227 if (!AddResource(id, dri2DrawableRes, pPriv)) 228 return BadAlloc; 229 230 ref->id = id; 231 ref->dri2_id = dri2_id; 232 ref->invalidate = invalidate; 233 ref->priv = priv; 234 list_add(&ref->link, &pPriv->reference_list); 235 236 return Success; 237} 238 239int 240DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id, 241 DRI2InvalidateProcPtr invalidate, void *priv) 242{ 243 DRI2DrawablePtr pPriv; 244 XID dri2_id; 245 int rc; 246 247 pPriv = DRI2GetDrawable(pDraw); 248 if (pPriv == NULL) 249 pPriv = DRI2AllocateDrawable(pDraw); 250 if (pPriv == NULL) 251 return BadAlloc; 252 253 dri2_id = FakeClientID(client->index); 254 rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv); 255 if (rc != Success) 256 return rc; 257 258 return Success; 259} 260 261static int DRI2DrawableGone(pointer p, XID id) 262{ 263 DRI2DrawablePtr pPriv = p; 264 DRI2ScreenPtr ds = pPriv->dri2_screen; 265 DRI2DrawableRefPtr ref, next; 266 WindowPtr pWin; 267 PixmapPtr pPixmap; 268 DrawablePtr pDraw; 269 int i; 270 271 list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) { 272 if (ref->dri2_id == id) { 273 list_del(&ref->link); 274 /* If this was the last ref under this X drawable XID, 275 * unregister the X drawable resource. */ 276 if (!DRI2LookupDrawableRef(pPriv, ref->id)) 277 FreeResourceByType(ref->id, dri2DrawableRes, TRUE); 278 free(ref); 279 break; 280 } 281 282 if (ref->id == id) { 283 list_del(&ref->link); 284 FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE); 285 free(ref); 286 } 287 } 288 289 if (!list_is_empty(&pPriv->reference_list)) 290 return Success; 291 292 pDraw = pPriv->drawable; 293 if (pDraw->type == DRAWABLE_WINDOW) { 294 pWin = (WindowPtr) pDraw; 295 dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL); 296 } else { 297 pPixmap = (PixmapPtr) pDraw; 298 dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL); 299 } 300 301 if (pPriv->buffers != NULL) { 302 for (i = 0; i < pPriv->bufferCount; i++) 303 (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); 304 305 free(pPriv->buffers); 306 } 307 308 free(pPriv); 309 310 return Success; 311} 312 313static int 314find_attachment(DRI2DrawablePtr pPriv, unsigned attachment) 315{ 316 int i; 317 318 if (pPriv->buffers == NULL) { 319 return -1; 320 } 321 322 for (i = 0; i < pPriv->bufferCount; i++) { 323 if ((pPriv->buffers[i] != NULL) 324 && (pPriv->buffers[i]->attachment == attachment)) { 325 return i; 326 } 327 } 328 329 return -1; 330} 331 332static Bool 333allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, 334 DRI2DrawablePtr pPriv, 335 unsigned int attachment, unsigned int format, 336 int dimensions_match, DRI2BufferPtr *buffer) 337{ 338 int old_buf = find_attachment(pPriv, attachment); 339 340 if ((old_buf < 0) 341 || !dimensions_match 342 || (pPriv->buffers[old_buf]->format != format)) { 343 *buffer = (*ds->CreateBuffer)(pDraw, attachment, format); 344 pPriv->serialNumber = DRI2DrawableSerial(pDraw); 345 return TRUE; 346 347 } else { 348 *buffer = pPriv->buffers[old_buf]; 349 pPriv->buffers[old_buf] = NULL; 350 return FALSE; 351 } 352} 353 354static void 355update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw, 356 DRI2BufferPtr *buffers, int *out_count, int *width, int *height) 357{ 358 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 359 int i; 360 361 if (pPriv->buffers != NULL) { 362 for (i = 0; i < pPriv->bufferCount; i++) { 363 if (pPriv->buffers[i] != NULL) { 364 (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); 365 } 366 } 367 368 free(pPriv->buffers); 369 } 370 371 pPriv->buffers = buffers; 372 pPriv->bufferCount = *out_count; 373 pPriv->width = pDraw->width; 374 pPriv->height = pDraw->height; 375 *width = pPriv->width; 376 *height = pPriv->height; 377} 378 379static DRI2BufferPtr * 380do_get_buffers(DrawablePtr pDraw, int *width, int *height, 381 unsigned int *attachments, int count, int *out_count, 382 int has_format) 383{ 384 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 385 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 386 DRI2BufferPtr *buffers; 387 int need_real_front = 0; 388 int need_fake_front = 0; 389 int have_fake_front = 0; 390 int front_format = 0; 391 int dimensions_match; 392 int buffers_changed = 0; 393 int i; 394 395 if (!pPriv) { 396 *width = pDraw->width; 397 *height = pDraw->height; 398 *out_count = 0; 399 return NULL; 400 } 401 402 dimensions_match = (pDraw->width == pPriv->width) 403 && (pDraw->height == pPriv->height) 404 && (pPriv->serialNumber == DRI2DrawableSerial(pDraw)); 405 406 buffers = malloc((count + 1) * sizeof(buffers[0])); 407 408 for (i = 0; i < count; i++) { 409 const unsigned attachment = *(attachments++); 410 const unsigned format = (has_format) ? *(attachments++) : 0; 411 412 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, 413 format, dimensions_match, 414 &buffers[i])) 415 buffers_changed = 1; 416 417 if (buffers[i] == NULL) 418 goto err_out; 419 420 /* If the drawable is a window and the front-buffer is requested, 421 * silently add the fake front-buffer to the list of requested 422 * attachments. The counting logic in the loop accounts for the case 423 * where the client requests both the fake and real front-buffer. 424 */ 425 if (attachment == DRI2BufferBackLeft) { 426 need_real_front++; 427 front_format = format; 428 } 429 430 if (attachment == DRI2BufferFrontLeft) { 431 need_real_front--; 432 front_format = format; 433 434 if (pDraw->type == DRAWABLE_WINDOW) { 435 need_fake_front++; 436 } 437 } 438 439 if (pDraw->type == DRAWABLE_WINDOW) { 440 if (attachment == DRI2BufferFakeFrontLeft) { 441 need_fake_front--; 442 have_fake_front = 1; 443 } 444 } 445 } 446 447 if (need_real_front > 0) { 448 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft, 449 front_format, dimensions_match, 450 &buffers[i])) 451 buffers_changed = 1; 452 453 if (buffers[i] == NULL) 454 goto err_out; 455 i++; 456 } 457 458 if (need_fake_front > 0) { 459 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft, 460 front_format, dimensions_match, 461 &buffers[i])) 462 buffers_changed = 1; 463 464 if (buffers[i] == NULL) 465 goto err_out; 466 467 i++; 468 have_fake_front = 1; 469 } 470 471 *out_count = i; 472 473 update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height); 474 475 /* If the client is getting a fake front-buffer, pre-fill it with the 476 * contents of the real front-buffer. This ensures correct operation of 477 * applications that call glXWaitX before calling glDrawBuffer. 478 */ 479 if (have_fake_front && buffers_changed) { 480 BoxRec box; 481 RegionRec region; 482 483 box.x1 = 0; 484 box.y1 = 0; 485 box.x2 = pPriv->width; 486 box.y2 = pPriv->height; 487 RegionInit(®ion, &box, 0); 488 489 DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 490 DRI2BufferFrontLeft); 491 } 492 493 return pPriv->buffers; 494 495err_out: 496 497 *out_count = 0; 498 499 for (i = 0; i < count; i++) { 500 if (buffers[i] != NULL) 501 (*ds->DestroyBuffer)(pDraw, buffers[i]); 502 } 503 504 free(buffers); 505 buffers = NULL; 506 507 update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height); 508 509 return buffers; 510} 511 512DRI2BufferPtr * 513DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height, 514 unsigned int *attachments, int count, int *out_count) 515{ 516 return do_get_buffers(pDraw, width, height, attachments, count, 517 out_count, FALSE); 518} 519 520DRI2BufferPtr * 521DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, 522 unsigned int *attachments, int count, int *out_count) 523{ 524 return do_get_buffers(pDraw, width, height, attachments, count, 525 out_count, TRUE); 526} 527 528static void 529DRI2InvalidateDrawable(DrawablePtr pDraw) 530{ 531 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 532 DRI2DrawableRefPtr ref; 533 534 if (!pPriv) 535 return; 536 537 list_for_each_entry(ref, &pPriv->reference_list, link) 538 ref->invalidate(pDraw, ref->priv); 539} 540 541/* 542 * In the direct rendered case, we throttle the clients that have more 543 * than their share of outstanding swaps (and thus busy buffers) when a 544 * new GetBuffers request is received. In the AIGLX case, we allow the 545 * client to get the new buffers, but throttle when the next GLX request 546 * comes in (see __glXDRIcontextWait()). 547 */ 548Bool 549DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw) 550{ 551 DRI2DrawablePtr pPriv; 552 553 pPriv = DRI2GetDrawable(pDraw); 554 if (pPriv == NULL) 555 return FALSE; 556 557 /* Throttle to swap limit */ 558 if ((pPriv->swapsPending >= pPriv->swap_limit) && 559 !pPriv->blockedClient) { 560 ResetCurrentRequest(client); 561 client->sequence--; 562 IgnoreClient(client); 563 pPriv->blockedClient = client; 564 return TRUE; 565 } 566 567 return FALSE; 568} 569 570static void 571__DRI2BlockClient(ClientPtr client, DRI2DrawablePtr pPriv) 572{ 573 if (pPriv->blockedClient == NULL) { 574 IgnoreClient(client); 575 pPriv->blockedClient = client; 576 } 577} 578 579void 580DRI2BlockClient(ClientPtr client, DrawablePtr pDraw) 581{ 582 DRI2DrawablePtr pPriv; 583 584 pPriv = DRI2GetDrawable(pDraw); 585 if (pPriv == NULL) 586 return; 587 588 __DRI2BlockClient(client, pPriv); 589 pPriv->blockedOnMsc = TRUE; 590} 591 592int 593DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, 594 unsigned int dest, unsigned int src) 595{ 596 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 597 DRI2DrawablePtr pPriv; 598 DRI2BufferPtr pDestBuffer, pSrcBuffer; 599 int i; 600 601 pPriv = DRI2GetDrawable(pDraw); 602 if (pPriv == NULL) 603 return BadDrawable; 604 605 pDestBuffer = NULL; 606 pSrcBuffer = NULL; 607 for (i = 0; i < pPriv->bufferCount; i++) 608 { 609 if (pPriv->buffers[i]->attachment == dest) 610 pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 611 if (pPriv->buffers[i]->attachment == src) 612 pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 613 } 614 if (pSrcBuffer == NULL || pDestBuffer == NULL) 615 return BadValue; 616 617 (*ds->CopyRegion)(pDraw, pRegion, pDestBuffer, pSrcBuffer); 618 619 return Success; 620} 621 622/* Can this drawable be page flipped? */ 623Bool 624DRI2CanFlip(DrawablePtr pDraw) 625{ 626 ScreenPtr pScreen = pDraw->pScreen; 627 WindowPtr pWin, pRoot; 628 PixmapPtr pWinPixmap, pRootPixmap; 629 630 if (pDraw->type == DRAWABLE_PIXMAP) 631 return TRUE; 632 633 pRoot = pScreen->root; 634 pRootPixmap = pScreen->GetWindowPixmap(pRoot); 635 636 pWin = (WindowPtr) pDraw; 637 pWinPixmap = pScreen->GetWindowPixmap(pWin); 638 if (pRootPixmap != pWinPixmap) 639 return FALSE; 640 if (!RegionEqual(&pWin->clipList, &pRoot->winSize)) 641 return FALSE; 642 643 /* Does the window match the pixmap exactly? */ 644 if (pDraw->x != 0 || 645 pDraw->y != 0 || 646#ifdef COMPOSITE 647 pDraw->x != pWinPixmap->screen_x || 648 pDraw->y != pWinPixmap->screen_y || 649#endif 650 pDraw->width != pWinPixmap->drawable.width || 651 pDraw->height != pWinPixmap->drawable.height) 652 return FALSE; 653 654 return TRUE; 655} 656 657/* Can we do a pixmap exchange instead of a blit? */ 658Bool 659DRI2CanExchange(DrawablePtr pDraw) 660{ 661 return FALSE; 662} 663 664void 665DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, 666 unsigned int tv_sec, unsigned int tv_usec) 667{ 668 DRI2DrawablePtr pPriv; 669 670 pPriv = DRI2GetDrawable(pDraw); 671 if (pPriv == NULL) 672 return; 673 674 ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, 675 frame, pPriv->swap_count); 676 677 if (pPriv->blockedClient) 678 AttendClient(pPriv->blockedClient); 679 680 pPriv->blockedClient = NULL; 681 pPriv->blockedOnMsc = FALSE; 682} 683 684static void 685DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame, 686 unsigned int tv_sec, unsigned int tv_usec) 687{ 688 ScreenPtr pScreen = pDraw->pScreen; 689 DRI2DrawablePtr pPriv; 690 691 pPriv = DRI2GetDrawable(pDraw); 692 if (pPriv == NULL) { 693 xf86DrvMsg(pScreen->myNum, X_ERROR, 694 "[DRI2] %s: bad drawable\n", __func__); 695 return; 696 } 697 698 /* 699 * Swap completed. 700 * Wake the client iff: 701 * - it was waiting on SBC 702 * - was blocked due to GLX make current 703 * - was blocked due to swap throttling 704 * - is not blocked due to an MSC wait 705 */ 706 if (pPriv->target_sbc != -1 && 707 pPriv->target_sbc <= pPriv->swap_count) { 708 ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, 709 frame, pPriv->swap_count); 710 pPriv->target_sbc = -1; 711 712 AttendClient(pPriv->blockedClient); 713 pPriv->blockedClient = NULL; 714 } else if (pPriv->target_sbc == -1 && !pPriv->blockedOnMsc) { 715 if (pPriv->blockedClient) { 716 AttendClient(pPriv->blockedClient); 717 pPriv->blockedClient = NULL; 718 } 719 } 720} 721 722void 723DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, 724 unsigned int tv_sec, unsigned int tv_usec, int type, 725 DRI2SwapEventPtr swap_complete, void *swap_data) 726{ 727 ScreenPtr pScreen = pDraw->pScreen; 728 DRI2DrawablePtr pPriv; 729 CARD64 ust = 0; 730 BoxRec box; 731 RegionRec region; 732 733 pPriv = DRI2GetDrawable(pDraw); 734 if (pPriv == NULL) { 735 xf86DrvMsg(pScreen->myNum, X_ERROR, 736 "[DRI2] %s: bad drawable\n", __func__); 737 return; 738 } 739 740 pPriv->swapsPending--; 741 pPriv->swap_count++; 742 743 box.x1 = 0; 744 box.y1 = 0; 745 box.x2 = pDraw->width; 746 box.y2 = pDraw->height; 747 RegionInit(®ion, &box, 0); 748 DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 749 DRI2BufferFrontLeft); 750 751 ust = ((CARD64)tv_sec * 1000000) + tv_usec; 752 if (swap_complete) 753 swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); 754 755 pPriv->last_swap_msc = frame; 756 pPriv->last_swap_ust = ust; 757 758 DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); 759} 760 761Bool 762DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) 763{ 764 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 765 766 /* If we're currently waiting for a swap on this drawable, reset 767 * the request and suspend the client. We only support one 768 * blocked client per drawable. */ 769 if ((pPriv->swapsPending) && 770 pPriv->blockedClient == NULL) { 771 ResetCurrentRequest(client); 772 client->sequence--; 773 __DRI2BlockClient(client, pPriv); 774 return TRUE; 775 } 776 777 return FALSE; 778} 779 780int 781DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 782 CARD64 divisor, CARD64 remainder, CARD64 *swap_target, 783 DRI2SwapEventPtr func, void *data) 784{ 785 ScreenPtr pScreen = pDraw->pScreen; 786 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 787 DRI2DrawablePtr pPriv; 788 DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; 789 int ret, i; 790 CARD64 ust, current_msc; 791 792 pPriv = DRI2GetDrawable(pDraw); 793 if (pPriv == NULL) { 794 xf86DrvMsg(pScreen->myNum, X_ERROR, 795 "[DRI2] %s: bad drawable\n", __func__); 796 return BadDrawable; 797 } 798 799 for (i = 0; i < pPriv->bufferCount; i++) { 800 if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft) 801 pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 802 if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft) 803 pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 804 } 805 if (pSrcBuffer == NULL || pDestBuffer == NULL) { 806 xf86DrvMsg(pScreen->myNum, X_ERROR, 807 "[DRI2] %s: drawable has no back or front?\n", __func__); 808 return BadDrawable; 809 } 810 811 /* Old DDX or no swap interval, just blit */ 812 if (!ds->ScheduleSwap || !pPriv->swap_interval) { 813 BoxRec box; 814 RegionRec region; 815 816 box.x1 = 0; 817 box.y1 = 0; 818 box.x2 = pDraw->width; 819 box.y2 = pDraw->height; 820 RegionInit(®ion, &box, 0); 821 822 pPriv->swapsPending++; 823 824 (*ds->CopyRegion)(pDraw, ®ion, pDestBuffer, pSrcBuffer); 825 DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE, 826 func, data); 827 return Success; 828 } 829 830 /* 831 * In the simple glXSwapBuffers case, all params will be 0, and we just 832 * need to schedule a swap for the last swap target + the swap interval. 833 */ 834 if (target_msc == 0 && divisor == 0 && remainder == 0) { 835 /* If the current vblank count of the drawable's crtc is lower 836 * than the count stored in last_swap_target from a previous swap 837 * then reinitialize last_swap_target to the current crtc's msc, 838 * otherwise the swap will hang. This will happen if the drawable 839 * is moved to a crtc with a lower refresh rate, or a crtc that just 840 * got enabled. 841 */ 842 if (ds->GetMSC) { 843 if (!(*ds->GetMSC)(pDraw, &ust, ¤t_msc)) 844 pPriv->last_swap_target = 0; 845 846 if (current_msc < pPriv->last_swap_target) 847 pPriv->last_swap_target = current_msc; 848 849 } 850 851 /* 852 * Swap target for this swap is last swap target + swap interval since 853 * we have to account for the current swap count, interval, and the 854 * number of pending swaps. 855 */ 856 *swap_target = pPriv->last_swap_target + pPriv->swap_interval; 857 858 } else { 859 /* glXSwapBuffersMscOML could have a 0 target_msc, honor it */ 860 *swap_target = target_msc; 861 } 862 863 pPriv->swapsPending++; 864 ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer, 865 swap_target, divisor, remainder, func, data); 866 if (!ret) { 867 pPriv->swapsPending--; /* didn't schedule */ 868 xf86DrvMsg(pScreen->myNum, X_ERROR, 869 "[DRI2] %s: driver failed to schedule swap\n", __func__); 870 return BadDrawable; 871 } 872 873 pPriv->last_swap_target = *swap_target; 874 875 /* According to spec, return expected swapbuffers count SBC after this swap 876 * will complete. 877 */ 878 *swap_target = pPriv->swap_count + pPriv->swapsPending; 879 880 DRI2InvalidateDrawable(pDraw); 881 882 return Success; 883} 884 885void 886DRI2SwapInterval(DrawablePtr pDrawable, int interval) 887{ 888 ScreenPtr pScreen = pDrawable->pScreen; 889 DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 890 891 if (pPriv == NULL) { 892 xf86DrvMsg(pScreen->myNum, X_ERROR, 893 "[DRI2] %s: bad drawable\n", __func__); 894 return; 895 } 896 897 /* fixme: check against arbitrary max? */ 898 pPriv->swap_interval = interval; 899} 900 901int 902DRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc, CARD64 *sbc) 903{ 904 ScreenPtr pScreen = pDraw->pScreen; 905 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 906 DRI2DrawablePtr pPriv; 907 Bool ret; 908 909 pPriv = DRI2GetDrawable(pDraw); 910 if (pPriv == NULL) { 911 xf86DrvMsg(pScreen->myNum, X_ERROR, 912 "[DRI2] %s: bad drawable\n", __func__); 913 return BadDrawable; 914 } 915 916 if (!ds->GetMSC) { 917 *ust = 0; 918 *msc = 0; 919 *sbc = pPriv->swap_count; 920 return Success; 921 } 922 923 /* 924 * Spec needs to be updated to include unmapped or redirected 925 * drawables 926 */ 927 928 ret = (*ds->GetMSC)(pDraw, ust, msc); 929 if (!ret) 930 return BadDrawable; 931 932 *sbc = pPriv->swap_count; 933 934 return Success; 935} 936 937int 938DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 939 CARD64 divisor, CARD64 remainder) 940{ 941 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 942 DRI2DrawablePtr pPriv; 943 Bool ret; 944 945 pPriv = DRI2GetDrawable(pDraw); 946 if (pPriv == NULL) 947 return BadDrawable; 948 949 /* Old DDX just completes immediately */ 950 if (!ds->ScheduleWaitMSC) { 951 DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0); 952 953 return Success; 954 } 955 956 ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder); 957 if (!ret) 958 return BadDrawable; 959 960 return Success; 961} 962 963int 964DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc) 965{ 966 DRI2DrawablePtr pPriv; 967 968 pPriv = DRI2GetDrawable(pDraw); 969 if (pPriv == NULL) 970 return BadDrawable; 971 972 /* target_sbc == 0 means to block until all pending swaps are 973 * finished. Recalculate target_sbc to get that behaviour. 974 */ 975 if (target_sbc == 0) 976 target_sbc = pPriv->swap_count + pPriv->swapsPending; 977 978 /* If current swap count already >= target_sbc, reply and 979 * return immediately with (ust, msc, sbc) triplet of 980 * most recent completed swap. 981 */ 982 if (pPriv->swap_count >= target_sbc) { 983 ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust, 984 pPriv->last_swap_msc, pPriv->swap_count); 985 return Success; 986 } 987 988 pPriv->target_sbc = target_sbc; 989 __DRI2BlockClient(client, pPriv); 990 991 return Success; 992} 993 994Bool 995DRI2HasSwapControl(ScreenPtr pScreen) 996{ 997 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 998 999 return ds->ScheduleSwap && ds->GetMSC; 1000} 1001 1002Bool 1003DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd, 1004 const char **driverName, const char **deviceName) 1005{ 1006 DRI2ScreenPtr ds; 1007 1008 if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 1009 return FALSE; 1010 1011 ds = DRI2GetScreen(pScreen); 1012 if (ds == NULL || driverType >= ds->numDrivers || 1013 !ds->driverNames[driverType]) 1014 return FALSE; 1015 1016 *fd = ds->fd; 1017 *driverName = ds->driverNames[driverType]; 1018 *deviceName = ds->deviceName; 1019 1020 return TRUE; 1021} 1022 1023Bool 1024DRI2Authenticate(ScreenPtr pScreen, uint32_t magic) 1025{ 1026 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1027 1028 if (ds == NULL || (*ds->AuthMagic)(ds->fd, magic)) 1029 return FALSE; 1030 1031 return TRUE; 1032} 1033 1034static int 1035DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw, 1036 WindowPtr pSib) 1037{ 1038 DrawablePtr pDraw = (DrawablePtr)pWin; 1039 ScreenPtr pScreen = pDraw->pScreen; 1040 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1041 DRI2DrawablePtr dd = DRI2GetDrawable(pDraw); 1042 int ret; 1043 1044 if (ds->ConfigNotify) { 1045 pScreen->ConfigNotify = ds->ConfigNotify; 1046 1047 ret = (*pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib); 1048 1049 ds->ConfigNotify = pScreen->ConfigNotify; 1050 pScreen->ConfigNotify = DRI2ConfigNotify; 1051 if (ret) 1052 return ret; 1053 } 1054 1055 if (!dd || (dd->width == w && dd->height == h)) 1056 return Success; 1057 1058 DRI2InvalidateDrawable(pDraw); 1059 return Success; 1060} 1061 1062Bool 1063DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) 1064{ 1065 DRI2ScreenPtr ds; 1066 const char* driverTypeNames[] = { 1067 "DRI", /* DRI2DriverDRI */ 1068 "VDPAU", /* DRI2DriverVDPAU */ 1069 }; 1070 unsigned int i; 1071 CARD8 cur_minor; 1072 1073 if (info->version < 3) 1074 return FALSE; 1075 1076 if (!xf86VGAarbiterAllowDRI(pScreen)) { 1077 xf86DrvMsg(pScreen->myNum, X_WARNING, 1078 "[DRI2] Direct rendering is not supported when VGA arb is necessary for the device\n"); 1079 return FALSE; 1080 } 1081 1082 if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 1083 return FALSE; 1084 1085 if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0)) 1086 return FALSE; 1087 1088 if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) 1089 return FALSE; 1090 1091 ds = calloc(1, sizeof *ds); 1092 if (!ds) 1093 return FALSE; 1094 1095 ds->screen = pScreen; 1096 ds->fd = info->fd; 1097 ds->deviceName = info->deviceName; 1098 dri2_major = 1; 1099 1100 ds->CreateBuffer = info->CreateBuffer; 1101 ds->DestroyBuffer = info->DestroyBuffer; 1102 ds->CopyRegion = info->CopyRegion; 1103 1104 if (info->version >= 4) { 1105 ds->ScheduleSwap = info->ScheduleSwap; 1106 ds->ScheduleWaitMSC = info->ScheduleWaitMSC; 1107 ds->GetMSC = info->GetMSC; 1108 cur_minor = 3; 1109 } else { 1110 cur_minor = 1; 1111 } 1112 1113 if (info->version >= 5) { 1114 ds->AuthMagic = info->AuthMagic; 1115 } 1116 1117 /* 1118 * if the driver doesn't provide an AuthMagic function or the info struct 1119 * version is too low, it relies on the old method (using libdrm) or fail 1120 */ 1121 if (!ds->AuthMagic) 1122#ifdef WITH_LIBDRM 1123 ds->AuthMagic = drmAuthMagic; 1124#else 1125 goto err_out; 1126#endif 1127 1128 /* Initialize minor if needed and set to minimum provied by DDX */ 1129 if (!dri2_minor || dri2_minor > cur_minor) 1130 dri2_minor = cur_minor; 1131 1132 if (info->version == 3 || info->numDrivers == 0) { 1133 /* Driver too old: use the old-style driverName field */ 1134 ds->numDrivers = 1; 1135 ds->driverNames = malloc(sizeof(*ds->driverNames)); 1136 if (!ds->driverNames) 1137 goto err_out; 1138 ds->driverNames[0] = info->driverName; 1139 } else { 1140 ds->numDrivers = info->numDrivers; 1141 ds->driverNames = malloc(info->numDrivers * sizeof(*ds->driverNames)); 1142 if (!ds->driverNames) 1143 goto err_out; 1144 memcpy(ds->driverNames, info->driverNames, 1145 info->numDrivers * sizeof(*ds->driverNames)); 1146 } 1147 1148 dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); 1149 1150 ds->ConfigNotify = pScreen->ConfigNotify; 1151 pScreen->ConfigNotify = DRI2ConfigNotify; 1152 1153 xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); 1154 for (i = 0; i < sizeof(driverTypeNames) / sizeof(driverTypeNames[0]); i++) { 1155 if (i < ds->numDrivers && ds->driverNames[i]) { 1156 xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] %s driver: %s\n", 1157 driverTypeNames[i], ds->driverNames[i]); 1158 } 1159 } 1160 1161 return TRUE; 1162 1163err_out: 1164 xf86DrvMsg(pScreen->myNum, X_WARNING, 1165 "[DRI2] Initialization failed for info version %d.\n", info->version); 1166 free(ds); 1167 return FALSE; 1168} 1169 1170void 1171DRI2CloseScreen(ScreenPtr pScreen) 1172{ 1173 DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1174 1175 free(ds->driverNames); 1176 free(ds); 1177 dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL); 1178} 1179 1180extern ExtensionModule dri2ExtensionModule; 1181 1182static pointer 1183DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin) 1184{ 1185 static Bool setupDone = FALSE; 1186 1187 dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable"); 1188 1189 if (!setupDone) 1190 { 1191 setupDone = TRUE; 1192 LoadExtension(&dri2ExtensionModule, FALSE); 1193 } 1194 else 1195 { 1196 if (errmaj) 1197 *errmaj = LDR_ONCEONLY; 1198 } 1199 1200 return (pointer) 1; 1201} 1202 1203static XF86ModuleVersionInfo DRI2VersRec = 1204{ 1205 "dri2", 1206 MODULEVENDORSTRING, 1207 MODINFOSTRING1, 1208 MODINFOSTRING2, 1209 XORG_VERSION_CURRENT, 1210 1, 2, 0, 1211 ABI_CLASS_EXTENSION, 1212 ABI_EXTENSION_VERSION, 1213 MOD_CLASS_NONE, 1214 { 0, 0, 0, 0 } 1215}; 1216 1217_X_EXPORT XF86ModuleData dri2ModuleData = { &DRI2VersRec, DRI2Setup, NULL }; 1218 1219void 1220DRI2Version(int *major, int *minor) 1221{ 1222 if (major != NULL) 1223 *major = DRI2VersRec.majorversion; 1224 1225 if (minor != NULL) 1226 *minor = DRI2VersRec.minorversion; 1227} 1228