dri2.c revision ab434f6b7641a64d30725a9ac24929240362d466
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 __GLXdisplayPrivate *glx_dpy = __glXInitialize(dpy); 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 xDRI2BufferSwapComplete *awire = (xDRI2BufferSwapComplete *)wire; 102 __GLXDRIdrawable *pdraw; 103 104 /* Ignore swap events if we're not looking for them */ 105 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, awire->drawable); 106 if (!(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) 107 return False; 108 109 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire); 110 aevent->type = glx_dpy->codes->first_event + GLX_BufferSwapComplete; 111 aevent->send_event = (awire->type & 0x80) != 0; 112 aevent->display = dpy; 113 aevent->drawable = awire->drawable; 114 switch (awire->event_type) { 115 case DRI2_EXCHANGE_COMPLETE: 116 aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL; 117 break; 118 case DRI2_BLIT_COMPLETE: 119 aevent->event_type = GLX_COPY_COMPLETE_INTEL; 120 break; 121 case DRI2_FLIP_COMPLETE: 122 aevent->event_type = GLX_FLIP_COMPLETE_INTEL; 123 break; 124 default: 125 /* unknown swap completion type */ 126 return False; 127 } 128 aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo; 129 aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo; 130 aevent->sbc = ((CARD64)awire->sbc_hi << 32) | awire->sbc_lo; 131 return True; 132 } 133#endif 134#ifdef DRI2_InvalidateBuffers 135 case DRI2_InvalidateBuffers: 136 { 137 xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire; 138 139 dri2InvalidateBuffers(dpy, awire->drawable); 140 return False; 141 } 142#endif 143 default: 144 /* client doesn't support server event */ 145 break; 146 } 147 148 return False; 149} 150 151/* We don't actually support this. It doesn't make sense for clients to 152 * send each other DRI2 events. 153 */ 154static Status 155DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire) 156{ 157 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 158 159 XextCheckExtension(dpy, info, dri2ExtensionName, False); 160 161 switch (event->type) { 162 default: 163 /* client doesn't support server event */ 164 break; 165 } 166 167 return Success; 168} 169 170static int 171DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code) 172{ 173 if (err->majorCode == codes->major_opcode && 174 err->errorCode == BadDrawable && 175 err->minorCode == X_DRI2CopyRegion) 176 return True; 177 178 return False; 179} 180 181Bool 182DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase) 183{ 184 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 185 186 if (XextHasExtension(info)) { 187 *eventBase = info->codes->first_event; 188 *errorBase = info->codes->first_error; 189 return True; 190 } 191 192 return False; 193} 194 195Bool 196DRI2QueryVersion(Display * dpy, int *major, int *minor) 197{ 198 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 199 xDRI2QueryVersionReply rep; 200 xDRI2QueryVersionReq *req; 201 int i, nevents; 202 203 XextCheckExtension(dpy, info, dri2ExtensionName, False); 204 205 LockDisplay(dpy); 206 GetReq(DRI2QueryVersion, req); 207 req->reqType = info->codes->major_opcode; 208 req->dri2ReqType = X_DRI2QueryVersion; 209 req->majorVersion = DRI2_MAJOR; 210 req->minorVersion = DRI2_MINOR; 211 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 212 UnlockDisplay(dpy); 213 SyncHandle(); 214 return False; 215 } 216 *major = rep.majorVersion; 217 *minor = rep.minorVersion; 218 UnlockDisplay(dpy); 219 SyncHandle(); 220 221 switch (rep.minorVersion) { 222 case 1: 223 nevents = 0; 224 break; 225 case 2: 226 nevents = 1; 227 break; 228 case 3: 229 default: 230 nevents = 2; 231 break; 232 } 233 234 for (i = 0; i < nevents; i++) { 235 XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent); 236 XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire); 237 } 238 239 return True; 240} 241 242Bool 243DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName) 244{ 245 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 246 xDRI2ConnectReply rep; 247 xDRI2ConnectReq *req; 248 249 XextCheckExtension(dpy, info, dri2ExtensionName, False); 250 251 LockDisplay(dpy); 252 GetReq(DRI2Connect, req); 253 req->reqType = info->codes->major_opcode; 254 req->dri2ReqType = X_DRI2Connect; 255 req->window = window; 256 req->driverType = DRI2DriverDRI; 257 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 258 UnlockDisplay(dpy); 259 SyncHandle(); 260 return False; 261 } 262 263 if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) { 264 UnlockDisplay(dpy); 265 SyncHandle(); 266 return False; 267 } 268 269 *driverName = Xmalloc(rep.driverNameLength + 1); 270 if (*driverName == NULL) { 271 _XEatData(dpy, 272 ((rep.driverNameLength + 3) & ~3) + 273 ((rep.deviceNameLength + 3) & ~3)); 274 UnlockDisplay(dpy); 275 SyncHandle(); 276 return False; 277 } 278 _XReadPad(dpy, *driverName, rep.driverNameLength); 279 (*driverName)[rep.driverNameLength] = '\0'; 280 281 *deviceName = Xmalloc(rep.deviceNameLength + 1); 282 if (*deviceName == NULL) { 283 Xfree(*driverName); 284 _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3)); 285 UnlockDisplay(dpy); 286 SyncHandle(); 287 return False; 288 } 289 _XReadPad(dpy, *deviceName, rep.deviceNameLength); 290 (*deviceName)[rep.deviceNameLength] = '\0'; 291 292 UnlockDisplay(dpy); 293 SyncHandle(); 294 295 return True; 296} 297 298Bool 299DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic) 300{ 301 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 302 xDRI2AuthenticateReq *req; 303 xDRI2AuthenticateReply rep; 304 305 XextCheckExtension(dpy, info, dri2ExtensionName, False); 306 307 LockDisplay(dpy); 308 GetReq(DRI2Authenticate, req); 309 req->reqType = info->codes->major_opcode; 310 req->dri2ReqType = X_DRI2Authenticate; 311 req->window = window; 312 req->magic = magic; 313 314 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 315 UnlockDisplay(dpy); 316 SyncHandle(); 317 return False; 318 } 319 320 UnlockDisplay(dpy); 321 SyncHandle(); 322 323 return rep.authenticated; 324} 325 326void 327DRI2CreateDrawable(Display * dpy, XID drawable) 328{ 329 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 330 xDRI2CreateDrawableReq *req; 331 332 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 333 334 LockDisplay(dpy); 335 GetReq(DRI2CreateDrawable, req); 336 req->reqType = info->codes->major_opcode; 337 req->dri2ReqType = X_DRI2CreateDrawable; 338 req->drawable = drawable; 339 UnlockDisplay(dpy); 340 SyncHandle(); 341} 342 343void 344DRI2DestroyDrawable(Display * dpy, XID drawable) 345{ 346 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 347 xDRI2DestroyDrawableReq *req; 348 349 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 350 351 XSync(dpy, False); 352 353 LockDisplay(dpy); 354 GetReq(DRI2DestroyDrawable, req); 355 req->reqType = info->codes->major_opcode; 356 req->dri2ReqType = X_DRI2DestroyDrawable; 357 req->drawable = drawable; 358 UnlockDisplay(dpy); 359 SyncHandle(); 360} 361 362DRI2Buffer * 363DRI2GetBuffers(Display * dpy, XID drawable, 364 int *width, int *height, 365 unsigned int *attachments, int count, int *outCount) 366{ 367 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 368 xDRI2GetBuffersReply rep; 369 xDRI2GetBuffersReq *req; 370 DRI2Buffer *buffers; 371 xDRI2Buffer repBuffer; 372 CARD32 *p; 373 int i; 374 375 XextCheckExtension(dpy, info, dri2ExtensionName, False); 376 377 LockDisplay(dpy); 378 GetReqExtra(DRI2GetBuffers, count * 4, req); 379 req->reqType = info->codes->major_opcode; 380 req->dri2ReqType = X_DRI2GetBuffers; 381 req->drawable = drawable; 382 req->count = count; 383 p = (CARD32 *) & req[1]; 384 for (i = 0; i < count; i++) 385 p[i] = attachments[i]; 386 387 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 388 UnlockDisplay(dpy); 389 SyncHandle(); 390 return NULL; 391 } 392 393 *width = rep.width; 394 *height = rep.height; 395 *outCount = rep.count; 396 397 buffers = Xmalloc(rep.count * sizeof buffers[0]); 398 if (buffers == NULL) { 399 _XEatData(dpy, rep.count * sizeof repBuffer); 400 UnlockDisplay(dpy); 401 SyncHandle(); 402 return NULL; 403 } 404 405 for (i = 0; i < rep.count; i++) { 406 _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); 407 buffers[i].attachment = repBuffer.attachment; 408 buffers[i].name = repBuffer.name; 409 buffers[i].pitch = repBuffer.pitch; 410 buffers[i].cpp = repBuffer.cpp; 411 buffers[i].flags = repBuffer.flags; 412 } 413 414 UnlockDisplay(dpy); 415 SyncHandle(); 416 417 return buffers; 418} 419 420 421DRI2Buffer * 422DRI2GetBuffersWithFormat(Display * dpy, XID drawable, 423 int *width, int *height, 424 unsigned int *attachments, int count, int *outCount) 425{ 426 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 427 xDRI2GetBuffersReply rep; 428 xDRI2GetBuffersReq *req; 429 DRI2Buffer *buffers; 430 xDRI2Buffer repBuffer; 431 CARD32 *p; 432 int i; 433 434 XextCheckExtension(dpy, info, dri2ExtensionName, False); 435 436 LockDisplay(dpy); 437 GetReqExtra(DRI2GetBuffers, count * (4 * 2), req); 438 req->reqType = info->codes->major_opcode; 439 req->dri2ReqType = X_DRI2GetBuffersWithFormat; 440 req->drawable = drawable; 441 req->count = count; 442 p = (CARD32 *) & req[1]; 443 for (i = 0; i < (count * 2); i++) 444 p[i] = attachments[i]; 445 446 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 447 UnlockDisplay(dpy); 448 SyncHandle(); 449 return NULL; 450 } 451 452 *width = rep.width; 453 *height = rep.height; 454 *outCount = rep.count; 455 456 buffers = Xmalloc(rep.count * sizeof buffers[0]); 457 if (buffers == NULL) { 458 _XEatData(dpy, rep.count * sizeof repBuffer); 459 UnlockDisplay(dpy); 460 SyncHandle(); 461 return NULL; 462 } 463 464 for (i = 0; i < rep.count; i++) { 465 _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); 466 buffers[i].attachment = repBuffer.attachment; 467 buffers[i].name = repBuffer.name; 468 buffers[i].pitch = repBuffer.pitch; 469 buffers[i].cpp = repBuffer.cpp; 470 buffers[i].flags = repBuffer.flags; 471 } 472 473 UnlockDisplay(dpy); 474 SyncHandle(); 475 476 return buffers; 477} 478 479 480void 481DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region, 482 CARD32 dest, CARD32 src) 483{ 484 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 485 xDRI2CopyRegionReq *req; 486 xDRI2CopyRegionReply rep; 487 488 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 489 490 LockDisplay(dpy); 491 GetReq(DRI2CopyRegion, req); 492 req->reqType = info->codes->major_opcode; 493 req->dri2ReqType = X_DRI2CopyRegion; 494 req->drawable = drawable; 495 req->region = region; 496 req->dest = dest; 497 req->src = src; 498 499 _XReply(dpy, (xReply *) & rep, 0, xFalse); 500 501 UnlockDisplay(dpy); 502 SyncHandle(); 503} 504 505#ifdef X_DRI2SwapBuffers 506static void 507load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor, 508 CARD64 remainder) 509{ 510 req->target_msc_hi = target >> 32; 511 req->target_msc_lo = target & 0xffffffff; 512 req->divisor_hi = divisor >> 32; 513 req->divisor_lo = divisor & 0xffffffff; 514 req->remainder_hi = remainder >> 32; 515 req->remainder_lo = remainder & 0xffffffff; 516} 517 518static CARD64 519vals_to_card64(CARD32 lo, CARD32 hi) 520{ 521 return (CARD64)hi << 32 | lo; 522} 523 524void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc, 525 CARD64 divisor, CARD64 remainder, CARD64 *count) 526{ 527 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 528 xDRI2SwapBuffersReq *req; 529 xDRI2SwapBuffersReply rep; 530 531 XextSimpleCheckExtension (dpy, info, dri2ExtensionName); 532 533 LockDisplay(dpy); 534 GetReq(DRI2SwapBuffers, req); 535 req->reqType = info->codes->major_opcode; 536 req->dri2ReqType = X_DRI2SwapBuffers; 537 req->drawable = drawable; 538 load_swap_req(req, target_msc, divisor, remainder); 539 540 _XReply(dpy, (xReply *)&rep, 0, xFalse); 541 542 *count = vals_to_card64(rep.swap_lo, rep.swap_hi); 543 544 UnlockDisplay(dpy); 545 SyncHandle(); 546} 547#endif 548 549#ifdef X_DRI2GetMSC 550Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc, 551 CARD64 *sbc) 552{ 553 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 554 xDRI2GetMSCReq *req; 555 xDRI2MSCReply rep; 556 557 XextCheckExtension (dpy, info, dri2ExtensionName, False); 558 559 LockDisplay(dpy); 560 GetReq(DRI2GetMSC, req); 561 req->reqType = info->codes->major_opcode; 562 req->dri2ReqType = X_DRI2GetMSC; 563 req->drawable = drawable; 564 565 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 566 UnlockDisplay(dpy); 567 SyncHandle(); 568 return False; 569 } 570 571 *ust = vals_to_card64(rep.ust_lo, rep.ust_hi); 572 *msc = vals_to_card64(rep.msc_lo, rep.msc_hi); 573 *sbc = vals_to_card64(rep.sbc_lo, rep.sbc_hi); 574 575 UnlockDisplay(dpy); 576 SyncHandle(); 577 578 return True; 579} 580#endif 581 582#ifdef X_DRI2WaitMSC 583static void 584load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor, 585 CARD64 remainder) 586{ 587 req->target_msc_hi = target >> 32; 588 req->target_msc_lo = target & 0xffffffff; 589 req->divisor_hi = divisor >> 32; 590 req->divisor_lo = divisor & 0xffffffff; 591 req->remainder_hi = remainder >> 32; 592 req->remainder_lo = remainder & 0xffffffff; 593} 594 595Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor, 596 CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc) 597{ 598 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 599 xDRI2WaitMSCReq *req; 600 xDRI2MSCReply rep; 601 602 XextCheckExtension (dpy, info, dri2ExtensionName, False); 603 604 LockDisplay(dpy); 605 GetReq(DRI2WaitMSC, req); 606 req->reqType = info->codes->major_opcode; 607 req->dri2ReqType = X_DRI2WaitMSC; 608 req->drawable = drawable; 609 load_msc_req(req, target_msc, divisor, remainder); 610 611 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 612 UnlockDisplay(dpy); 613 SyncHandle(); 614 return False; 615 } 616 617 *ust = ((CARD64)rep.ust_hi << 32) | (CARD64)rep.ust_lo; 618 *msc = ((CARD64)rep.msc_hi << 32) | (CARD64)rep.msc_lo; 619 *sbc = ((CARD64)rep.sbc_hi << 32) | (CARD64)rep.sbc_lo; 620 621 UnlockDisplay(dpy); 622 SyncHandle(); 623 624 return True; 625} 626#endif 627 628#ifdef X_DRI2WaitSBC 629static void 630load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target) 631{ 632 req->target_sbc_hi = target >> 32; 633 req->target_sbc_lo = target & 0xffffffff; 634} 635 636Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust, 637 CARD64 *msc, CARD64 *sbc) 638{ 639 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 640 xDRI2WaitSBCReq *req; 641 xDRI2MSCReply rep; 642 643 XextCheckExtension (dpy, info, dri2ExtensionName, False); 644 645 LockDisplay(dpy); 646 GetReq(DRI2WaitSBC, req); 647 req->reqType = info->codes->major_opcode; 648 req->dri2ReqType = X_DRI2WaitSBC; 649 req->drawable = drawable; 650 load_sbc_req(req, target_sbc); 651 652 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 653 UnlockDisplay(dpy); 654 SyncHandle(); 655 return False; 656 } 657 658 *ust = ((CARD64)rep.ust_hi << 32) | rep.ust_lo; 659 *msc = ((CARD64)rep.msc_hi << 32) | rep.msc_lo; 660 *sbc = ((CARD64)rep.sbc_hi << 32) | rep.sbc_lo; 661 662 UnlockDisplay(dpy); 663 SyncHandle(); 664 665 return True; 666} 667#endif 668 669#ifdef X_DRI2SwapInterval 670void DRI2SwapInterval(Display *dpy, XID drawable, int interval) 671{ 672 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 673 xDRI2SwapIntervalReq *req; 674 675 XextSimpleCheckExtension (dpy, info, dri2ExtensionName); 676 677 LockDisplay(dpy); 678 GetReq(DRI2SwapInterval, req); 679 req->reqType = info->codes->major_opcode; 680 req->dri2ReqType = X_DRI2SwapInterval; 681 req->drawable = drawable; 682 req->interval = interval; 683 UnlockDisplay(dpy); 684 SyncHandle(); 685} 686#endif 687 688#endif /* GLX_DIRECT_RENDERING */ 689