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