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