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