1/* 2 * Copyright © 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 34#ifdef GLX_DIRECT_RENDERING 35 36#include <stdio.h> 37#include <X11/Xlibint.h> 38#include <X11/extensions/Xext.h> 39#include <X11/extensions/extutil.h> 40#include <X11/extensions/dri2proto.h> 41#include "xf86drm.h" 42#include "dri2.h" 43#include "glxclient.h" 44#include "GL/glxext.h" 45 46/* Allow the build to work with an older versions of dri2proto.h and 47 * dri2tokens.h. 48 */ 49#if DRI2_MINOR < 1 50#undef DRI2_MINOR 51#define DRI2_MINOR 1 52#define X_DRI2GetBuffersWithFormat 7 53#endif 54 55 56static char dri2ExtensionName[] = DRI2_NAME; 57static XExtensionInfo *dri2Info; 58static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info) 59 60static Bool 61DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire); 62static Status 63DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire); 64static int 65DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code); 66 67static /* const */ XExtensionHooks dri2ExtensionHooks = { 68 NULL, /* create_gc */ 69 NULL, /* copy_gc */ 70 NULL, /* flush_gc */ 71 NULL, /* free_gc */ 72 NULL, /* create_font */ 73 NULL, /* free_font */ 74 DRI2CloseDisplay, /* close_display */ 75 DRI2WireToEvent, /* wire_to_event */ 76 DRI2EventToWire, /* event_to_wire */ 77 DRI2Error, /* error */ 78 NULL, /* error_string */ 79}; 80 81static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay, 82 dri2Info, 83 dri2ExtensionName, 84 &dri2ExtensionHooks, 85 0, NULL) 86 87static Bool 88DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire) 89{ 90 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 91 struct glx_drawable *glxDraw; 92 93 XextCheckExtension(dpy, info, dri2ExtensionName, False); 94 95 switch ((wire->u.u.type & 0x7f) - info->codes->first_event) { 96 97#ifdef X_DRI2SwapBuffers 98 case DRI2_BufferSwapComplete: 99 { 100 GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event; 101 xDRI2BufferSwapComplete2 *awire = (xDRI2BufferSwapComplete2 *)wire; 102 __GLXDRIdrawable *pdraw; 103 104 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, awire->drawable); 105 106 /* Ignore swap events if we're not looking for them */ 107 aevent->type = dri2GetSwapEventType(dpy, awire->drawable); 108 if(!aevent->type) 109 return False; 110 111 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire); 112 aevent->send_event = (awire->type & 0x80) != 0; 113 aevent->display = dpy; 114 aevent->drawable = awire->drawable; 115 switch (awire->event_type) { 116 case DRI2_EXCHANGE_COMPLETE: 117 aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL; 118 break; 119 case DRI2_BLIT_COMPLETE: 120 aevent->event_type = GLX_COPY_COMPLETE_INTEL; 121 break; 122 case DRI2_FLIP_COMPLETE: 123 aevent->event_type = GLX_FLIP_COMPLETE_INTEL; 124 break; 125 default: 126 /* unknown swap completion type */ 127 return False; 128 } 129 aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo; 130 aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo; 131 132 glxDraw = GetGLXDrawable(dpy, pdraw->drawable); 133 if (awire->sbc < glxDraw->lastEventSbc) 134 glxDraw->eventSbcWrap += 0x100000000; 135 glxDraw->lastEventSbc = awire->sbc; 136 aevent->sbc = awire->sbc + glxDraw->eventSbcWrap; 137 138 return True; 139 } 140#endif 141#ifdef DRI2_InvalidateBuffers 142 case DRI2_InvalidateBuffers: 143 { 144 xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire; 145 146 dri2InvalidateBuffers(dpy, awire->drawable); 147 return False; 148 } 149#endif 150 default: 151 /* client doesn't support server event */ 152 break; 153 } 154 155 return False; 156} 157 158/* We don't actually support this. It doesn't make sense for clients to 159 * send each other DRI2 events. 160 */ 161static Status 162DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire) 163{ 164 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 165 166 XextCheckExtension(dpy, info, dri2ExtensionName, False); 167 168 switch (event->type) { 169 default: 170 /* client doesn't support server event */ 171 break; 172 } 173 174 return Success; 175} 176 177static int 178DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code) 179{ 180 if (err->majorCode == codes->major_opcode && 181 err->errorCode == BadDrawable && 182 err->minorCode == X_DRI2CopyRegion) 183 return True; 184 185 /* If the X drawable was destroyed before the GLX drawable, the 186 * DRI2 drawble will be gone by the time we call 187 * DRI2DestroyDrawable. So just ignore BadDrawable here. */ 188 if (err->majorCode == codes->major_opcode && 189 err->errorCode == BadDrawable && 190 err->minorCode == X_DRI2DestroyDrawable) 191 return True; 192 193 /* If the server is non-local DRI2Connect will raise BadRequest. 194 * Swallow this so that DRI2Connect can signal this in its return code */ 195 if (err->majorCode == codes->major_opcode && 196 err->minorCode == X_DRI2Connect && 197 err->errorCode == BadRequest) { 198 *ret_code = False; 199 return True; 200 } 201 202 return False; 203} 204 205Bool 206DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase) 207{ 208 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 209 210 if (XextHasExtension(info)) { 211 *eventBase = info->codes->first_event; 212 *errorBase = info->codes->first_error; 213 return True; 214 } 215 216 return False; 217} 218 219Bool 220DRI2QueryVersion(Display * dpy, int *major, int *minor) 221{ 222 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 223 xDRI2QueryVersionReply rep; 224 xDRI2QueryVersionReq *req; 225 int i, nevents; 226 227 XextCheckExtension(dpy, info, dri2ExtensionName, False); 228 229 LockDisplay(dpy); 230 GetReq(DRI2QueryVersion, req); 231 req->reqType = info->codes->major_opcode; 232 req->dri2ReqType = X_DRI2QueryVersion; 233 req->majorVersion = DRI2_MAJOR; 234 req->minorVersion = DRI2_MINOR; 235 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 236 UnlockDisplay(dpy); 237 SyncHandle(); 238 return False; 239 } 240 *major = rep.majorVersion; 241 *minor = rep.minorVersion; 242 UnlockDisplay(dpy); 243 SyncHandle(); 244 245 switch (rep.minorVersion) { 246 case 1: 247 nevents = 0; 248 break; 249 case 2: 250 nevents = 1; 251 break; 252 case 3: 253 default: 254 nevents = 2; 255 break; 256 } 257 258 for (i = 0; i < nevents; i++) { 259 XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent); 260 XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire); 261 } 262 263 return True; 264} 265 266Bool 267DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName) 268{ 269 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 270 xDRI2ConnectReply rep; 271 xDRI2ConnectReq *req; 272 char *prime; 273 274 XextCheckExtension(dpy, info, dri2ExtensionName, False); 275 276 LockDisplay(dpy); 277 GetReq(DRI2Connect, req); 278 req->reqType = info->codes->major_opcode; 279 req->dri2ReqType = X_DRI2Connect; 280 req->window = window; 281 282 req->driverType = DRI2DriverDRI; 283#ifdef DRI2DriverPrimeShift 284 prime = getenv("DRI_PRIME"); 285 if (prime) { 286 uint32_t primeid; 287 errno = 0; 288 primeid = strtoul(prime, NULL, 0); 289 if (errno == 0) 290 req->driverType |= ((primeid & DRI2DriverPrimeMask) << DRI2DriverPrimeShift); 291 } 292#endif 293 294 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 295 UnlockDisplay(dpy); 296 SyncHandle(); 297 return False; 298 } 299 300 if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) { 301 UnlockDisplay(dpy); 302 SyncHandle(); 303 return False; 304 } 305 306 *driverName = Xmalloc(rep.driverNameLength + 1); 307 if (*driverName == NULL) { 308 _XEatData(dpy, 309 ((rep.driverNameLength + 3) & ~3) + 310 ((rep.deviceNameLength + 3) & ~3)); 311 UnlockDisplay(dpy); 312 SyncHandle(); 313 return False; 314 } 315 _XReadPad(dpy, *driverName, rep.driverNameLength); 316 (*driverName)[rep.driverNameLength] = '\0'; 317 318 *deviceName = Xmalloc(rep.deviceNameLength + 1); 319 if (*deviceName == NULL) { 320 Xfree(*driverName); 321 _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3)); 322 UnlockDisplay(dpy); 323 SyncHandle(); 324 return False; 325 } 326 _XReadPad(dpy, *deviceName, rep.deviceNameLength); 327 (*deviceName)[rep.deviceNameLength] = '\0'; 328 329 UnlockDisplay(dpy); 330 SyncHandle(); 331 332 return True; 333} 334 335Bool 336DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic) 337{ 338 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 339 xDRI2AuthenticateReq *req; 340 xDRI2AuthenticateReply rep; 341 342 XextCheckExtension(dpy, info, dri2ExtensionName, False); 343 344 LockDisplay(dpy); 345 GetReq(DRI2Authenticate, req); 346 req->reqType = info->codes->major_opcode; 347 req->dri2ReqType = X_DRI2Authenticate; 348 req->window = window; 349 req->magic = magic; 350 351 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 352 UnlockDisplay(dpy); 353 SyncHandle(); 354 return False; 355 } 356 357 UnlockDisplay(dpy); 358 SyncHandle(); 359 360 return rep.authenticated; 361} 362 363void 364DRI2CreateDrawable(Display * dpy, XID drawable) 365{ 366 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 367 xDRI2CreateDrawableReq *req; 368 369 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 370 371 LockDisplay(dpy); 372 GetReq(DRI2CreateDrawable, req); 373 req->reqType = info->codes->major_opcode; 374 req->dri2ReqType = X_DRI2CreateDrawable; 375 req->drawable = drawable; 376 UnlockDisplay(dpy); 377 SyncHandle(); 378} 379 380void 381DRI2DestroyDrawable(Display * dpy, XID drawable) 382{ 383 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 384 xDRI2DestroyDrawableReq *req; 385 386 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 387 388 XSync(dpy, False); 389 390 LockDisplay(dpy); 391 GetReq(DRI2DestroyDrawable, req); 392 req->reqType = info->codes->major_opcode; 393 req->dri2ReqType = X_DRI2DestroyDrawable; 394 req->drawable = drawable; 395 UnlockDisplay(dpy); 396 SyncHandle(); 397} 398 399DRI2Buffer * 400DRI2GetBuffers(Display * dpy, XID drawable, 401 int *width, int *height, 402 unsigned int *attachments, int count, int *outCount) 403{ 404 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 405 xDRI2GetBuffersReply rep; 406 xDRI2GetBuffersReq *req; 407 DRI2Buffer *buffers; 408 xDRI2Buffer repBuffer; 409 CARD32 *p; 410 int i; 411 412 XextCheckExtension(dpy, info, dri2ExtensionName, False); 413 414 LockDisplay(dpy); 415 GetReqExtra(DRI2GetBuffers, count * 4, req); 416 req->reqType = info->codes->major_opcode; 417 req->dri2ReqType = X_DRI2GetBuffers; 418 req->drawable = drawable; 419 req->count = count; 420 p = (CARD32 *) & req[1]; 421 for (i = 0; i < count; i++) 422 p[i] = attachments[i]; 423 424 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 425 UnlockDisplay(dpy); 426 SyncHandle(); 427 return NULL; 428 } 429 430 *width = rep.width; 431 *height = rep.height; 432 *outCount = rep.count; 433 434 buffers = Xmalloc(rep.count * sizeof buffers[0]); 435 if (buffers == NULL) { 436 _XEatData(dpy, rep.count * sizeof repBuffer); 437 UnlockDisplay(dpy); 438 SyncHandle(); 439 return NULL; 440 } 441 442 for (i = 0; i < rep.count; i++) { 443 _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); 444 buffers[i].attachment = repBuffer.attachment; 445 buffers[i].name = repBuffer.name; 446 buffers[i].pitch = repBuffer.pitch; 447 buffers[i].cpp = repBuffer.cpp; 448 buffers[i].flags = repBuffer.flags; 449 } 450 451 UnlockDisplay(dpy); 452 SyncHandle(); 453 454 return buffers; 455} 456 457 458DRI2Buffer * 459DRI2GetBuffersWithFormat(Display * dpy, XID drawable, 460 int *width, int *height, 461 unsigned int *attachments, int count, int *outCount) 462{ 463 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 464 xDRI2GetBuffersReply rep; 465 xDRI2GetBuffersReq *req; 466 DRI2Buffer *buffers; 467 xDRI2Buffer repBuffer; 468 CARD32 *p; 469 int i; 470 471 XextCheckExtension(dpy, info, dri2ExtensionName, False); 472 473 LockDisplay(dpy); 474 GetReqExtra(DRI2GetBuffers, count * (4 * 2), req); 475 req->reqType = info->codes->major_opcode; 476 req->dri2ReqType = X_DRI2GetBuffersWithFormat; 477 req->drawable = drawable; 478 req->count = count; 479 p = (CARD32 *) & req[1]; 480 for (i = 0; i < (count * 2); i++) 481 p[i] = attachments[i]; 482 483 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 484 UnlockDisplay(dpy); 485 SyncHandle(); 486 return NULL; 487 } 488 489 *width = rep.width; 490 *height = rep.height; 491 *outCount = rep.count; 492 493 buffers = Xmalloc(rep.count * sizeof buffers[0]); 494 if (buffers == NULL) { 495 _XEatData(dpy, rep.count * sizeof repBuffer); 496 UnlockDisplay(dpy); 497 SyncHandle(); 498 return NULL; 499 } 500 501 for (i = 0; i < rep.count; i++) { 502 _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); 503 buffers[i].attachment = repBuffer.attachment; 504 buffers[i].name = repBuffer.name; 505 buffers[i].pitch = repBuffer.pitch; 506 buffers[i].cpp = repBuffer.cpp; 507 buffers[i].flags = repBuffer.flags; 508 } 509 510 UnlockDisplay(dpy); 511 SyncHandle(); 512 513 return buffers; 514} 515 516 517void 518DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region, 519 CARD32 dest, CARD32 src) 520{ 521 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 522 xDRI2CopyRegionReq *req; 523 xDRI2CopyRegionReply rep; 524 525 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 526 527 LockDisplay(dpy); 528 GetReq(DRI2CopyRegion, req); 529 req->reqType = info->codes->major_opcode; 530 req->dri2ReqType = X_DRI2CopyRegion; 531 req->drawable = drawable; 532 req->region = region; 533 req->dest = dest; 534 req->src = src; 535 536 _XReply(dpy, (xReply *) & rep, 0, xFalse); 537 538 UnlockDisplay(dpy); 539 SyncHandle(); 540} 541 542#ifdef X_DRI2SwapBuffers 543static void 544load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor, 545 CARD64 remainder) 546{ 547 req->target_msc_hi = target >> 32; 548 req->target_msc_lo = target & 0xffffffff; 549 req->divisor_hi = divisor >> 32; 550 req->divisor_lo = divisor & 0xffffffff; 551 req->remainder_hi = remainder >> 32; 552 req->remainder_lo = remainder & 0xffffffff; 553} 554 555static CARD64 556vals_to_card64(CARD32 lo, CARD32 hi) 557{ 558 return (CARD64)hi << 32 | lo; 559} 560 561void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc, 562 CARD64 divisor, CARD64 remainder, CARD64 *count) 563{ 564 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 565 xDRI2SwapBuffersReq *req; 566 xDRI2SwapBuffersReply rep; 567 568 XextSimpleCheckExtension (dpy, info, dri2ExtensionName); 569 570 LockDisplay(dpy); 571 GetReq(DRI2SwapBuffers, req); 572 req->reqType = info->codes->major_opcode; 573 req->dri2ReqType = X_DRI2SwapBuffers; 574 req->drawable = drawable; 575 load_swap_req(req, target_msc, divisor, remainder); 576 577 _XReply(dpy, (xReply *)&rep, 0, xFalse); 578 579 *count = vals_to_card64(rep.swap_lo, rep.swap_hi); 580 581 UnlockDisplay(dpy); 582 SyncHandle(); 583} 584#endif 585 586#ifdef X_DRI2GetMSC 587Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc, 588 CARD64 *sbc) 589{ 590 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 591 xDRI2GetMSCReq *req; 592 xDRI2MSCReply rep; 593 594 XextCheckExtension (dpy, info, dri2ExtensionName, False); 595 596 LockDisplay(dpy); 597 GetReq(DRI2GetMSC, req); 598 req->reqType = info->codes->major_opcode; 599 req->dri2ReqType = X_DRI2GetMSC; 600 req->drawable = drawable; 601 602 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 603 UnlockDisplay(dpy); 604 SyncHandle(); 605 return False; 606 } 607 608 *ust = vals_to_card64(rep.ust_lo, rep.ust_hi); 609 *msc = vals_to_card64(rep.msc_lo, rep.msc_hi); 610 *sbc = vals_to_card64(rep.sbc_lo, rep.sbc_hi); 611 612 UnlockDisplay(dpy); 613 SyncHandle(); 614 615 return True; 616} 617#endif 618 619#ifdef X_DRI2WaitMSC 620static void 621load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor, 622 CARD64 remainder) 623{ 624 req->target_msc_hi = target >> 32; 625 req->target_msc_lo = target & 0xffffffff; 626 req->divisor_hi = divisor >> 32; 627 req->divisor_lo = divisor & 0xffffffff; 628 req->remainder_hi = remainder >> 32; 629 req->remainder_lo = remainder & 0xffffffff; 630} 631 632Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor, 633 CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc) 634{ 635 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 636 xDRI2WaitMSCReq *req; 637 xDRI2MSCReply rep; 638 639 XextCheckExtension (dpy, info, dri2ExtensionName, False); 640 641 LockDisplay(dpy); 642 GetReq(DRI2WaitMSC, req); 643 req->reqType = info->codes->major_opcode; 644 req->dri2ReqType = X_DRI2WaitMSC; 645 req->drawable = drawable; 646 load_msc_req(req, target_msc, divisor, remainder); 647 648 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 649 UnlockDisplay(dpy); 650 SyncHandle(); 651 return False; 652 } 653 654 *ust = ((CARD64)rep.ust_hi << 32) | (CARD64)rep.ust_lo; 655 *msc = ((CARD64)rep.msc_hi << 32) | (CARD64)rep.msc_lo; 656 *sbc = ((CARD64)rep.sbc_hi << 32) | (CARD64)rep.sbc_lo; 657 658 UnlockDisplay(dpy); 659 SyncHandle(); 660 661 return True; 662} 663#endif 664 665#ifdef X_DRI2WaitSBC 666static void 667load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target) 668{ 669 req->target_sbc_hi = target >> 32; 670 req->target_sbc_lo = target & 0xffffffff; 671} 672 673Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust, 674 CARD64 *msc, CARD64 *sbc) 675{ 676 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 677 xDRI2WaitSBCReq *req; 678 xDRI2MSCReply rep; 679 680 XextCheckExtension (dpy, info, dri2ExtensionName, False); 681 682 LockDisplay(dpy); 683 GetReq(DRI2WaitSBC, req); 684 req->reqType = info->codes->major_opcode; 685 req->dri2ReqType = X_DRI2WaitSBC; 686 req->drawable = drawable; 687 load_sbc_req(req, target_sbc); 688 689 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 690 UnlockDisplay(dpy); 691 SyncHandle(); 692 return False; 693 } 694 695 *ust = ((CARD64)rep.ust_hi << 32) | rep.ust_lo; 696 *msc = ((CARD64)rep.msc_hi << 32) | rep.msc_lo; 697 *sbc = ((CARD64)rep.sbc_hi << 32) | rep.sbc_lo; 698 699 UnlockDisplay(dpy); 700 SyncHandle(); 701 702 return True; 703} 704#endif 705 706#ifdef X_DRI2SwapInterval 707void DRI2SwapInterval(Display *dpy, XID drawable, int interval) 708{ 709 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 710 xDRI2SwapIntervalReq *req; 711 712 XextSimpleCheckExtension (dpy, info, dri2ExtensionName); 713 714 LockDisplay(dpy); 715 GetReq(DRI2SwapInterval, req); 716 req->reqType = info->codes->major_opcode; 717 req->dri2ReqType = X_DRI2SwapInterval; 718 req->drawable = drawable; 719 req->interval = interval; 720 UnlockDisplay(dpy); 721 SyncHandle(); 722} 723#endif 724 725#endif /* GLX_DIRECT_RENDERING */ 726