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