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