dri2.c revision 848b8605
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 "dri2.h" 42#include "glxclient.h" 43#include "GL/glxext.h" 44 45/* Allow the build to work with an older versions of dri2proto.h and 46 * dri2tokens.h. 47 */ 48#if DRI2_MINOR < 1 49#undef DRI2_MINOR 50#define DRI2_MINOR 1 51#define X_DRI2GetBuffersWithFormat 7 52#endif 53 54 55static char dri2ExtensionName[] = DRI2_NAME; 56static XExtensionInfo *dri2Info; 57static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info) 58 59static Bool 60DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire); 61static Status 62DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire); 63static int 64DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code); 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 DRI2Error, /* 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 struct glx_drawable *glxDraw; 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 xDRI2BufferSwapComplete2 *awire = (xDRI2BufferSwapComplete2 *)wire; 101 __GLXDRIdrawable *pdraw; 102 103 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, awire->drawable); 104 if (pdraw == NULL) 105 return False; 106 107 /* Ignore swap events if we're not looking for them */ 108 aevent->type = dri2GetSwapEventType(dpy, awire->drawable); 109 if(!aevent->type) 110 return False; 111 112 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire); 113 aevent->send_event = (awire->type & 0x80) != 0; 114 aevent->display = dpy; 115 aevent->drawable = awire->drawable; 116 switch (awire->event_type) { 117 case DRI2_EXCHANGE_COMPLETE: 118 aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL; 119 break; 120 case DRI2_BLIT_COMPLETE: 121 aevent->event_type = GLX_COPY_COMPLETE_INTEL; 122 break; 123 case DRI2_FLIP_COMPLETE: 124 aevent->event_type = GLX_FLIP_COMPLETE_INTEL; 125 break; 126 default: 127 /* unknown swap completion type */ 128 return False; 129 } 130 aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo; 131 aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo; 132 133 glxDraw = GetGLXDrawable(dpy, pdraw->drawable); 134 if (glxDraw != NULL) { 135 if (awire->sbc < glxDraw->lastEventSbc) 136 glxDraw->eventSbcWrap += 0x100000000; 137 glxDraw->lastEventSbc = awire->sbc; 138 aevent->sbc = awire->sbc + glxDraw->eventSbcWrap; 139 } else { 140 aevent->sbc = awire->sbc; 141 } 142 143 return True; 144 } 145#endif 146#ifdef DRI2_InvalidateBuffers 147 case DRI2_InvalidateBuffers: 148 { 149 xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire; 150 151 dri2InvalidateBuffers(dpy, awire->drawable); 152 return False; 153 } 154#endif 155 default: 156 /* client doesn't support server event */ 157 break; 158 } 159 160 return False; 161} 162 163/* We don't actually support this. It doesn't make sense for clients to 164 * send each other DRI2 events. 165 */ 166static Status 167DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire) 168{ 169 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 170 171 XextCheckExtension(dpy, info, dri2ExtensionName, False); 172 173 switch (event->type) { 174 default: 175 /* client doesn't support server event */ 176 break; 177 } 178 179 return Success; 180} 181 182static int 183DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code) 184{ 185 if (err->majorCode == codes->major_opcode && 186 err->errorCode == BadDrawable && 187 err->minorCode == X_DRI2CopyRegion) 188 return True; 189 190 /* If the X drawable was destroyed before the GLX drawable, the 191 * DRI2 drawble will be gone by the time we call 192 * DRI2DestroyDrawable. So just ignore BadDrawable here. */ 193 if (err->majorCode == codes->major_opcode && 194 err->errorCode == BadDrawable && 195 err->minorCode == X_DRI2DestroyDrawable) 196 return True; 197 198 /* If the server is non-local DRI2Connect will raise BadRequest. 199 * Swallow this so that DRI2Connect can signal this in its return code */ 200 if (err->majorCode == codes->major_opcode && 201 err->minorCode == X_DRI2Connect && 202 err->errorCode == BadRequest) { 203 *ret_code = False; 204 return True; 205 } 206 207 return False; 208} 209 210Bool 211DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase) 212{ 213 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 214 215 if (XextHasExtension(info)) { 216 *eventBase = info->codes->first_event; 217 *errorBase = info->codes->first_error; 218 return True; 219 } 220 221 return False; 222} 223 224Bool 225DRI2QueryVersion(Display * dpy, int *major, int *minor) 226{ 227 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 228 xDRI2QueryVersionReply rep; 229 xDRI2QueryVersionReq *req; 230 int i, nevents; 231 232 XextCheckExtension(dpy, info, dri2ExtensionName, False); 233 234 LockDisplay(dpy); 235 GetReq(DRI2QueryVersion, req); 236 req->reqType = info->codes->major_opcode; 237 req->dri2ReqType = X_DRI2QueryVersion; 238 req->majorVersion = DRI2_MAJOR; 239 req->minorVersion = DRI2_MINOR; 240 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 241 UnlockDisplay(dpy); 242 SyncHandle(); 243 return False; 244 } 245 *major = rep.majorVersion; 246 *minor = rep.minorVersion; 247 UnlockDisplay(dpy); 248 SyncHandle(); 249 250 switch (rep.minorVersion) { 251 case 1: 252 nevents = 0; 253 break; 254 case 2: 255 nevents = 1; 256 break; 257 case 3: 258 default: 259 nevents = 2; 260 break; 261 } 262 263 for (i = 0; i < nevents; i++) { 264 XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent); 265 XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire); 266 } 267 268 return True; 269} 270 271Bool 272DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName) 273{ 274 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 275 xDRI2ConnectReply rep; 276 xDRI2ConnectReq *req; 277 278 XextCheckExtension(dpy, info, dri2ExtensionName, False); 279 280 LockDisplay(dpy); 281 GetReq(DRI2Connect, req); 282 req->reqType = info->codes->major_opcode; 283 req->dri2ReqType = X_DRI2Connect; 284 req->window = window; 285 286 req->driverType = DRI2DriverDRI; 287#ifdef DRI2DriverPrimeShift 288 { 289 char *prime = getenv("DRI_PRIME"); 290 if (prime) { 291 uint32_t primeid; 292 errno = 0; 293 primeid = strtoul(prime, NULL, 0); 294 if (errno == 0) 295 req->driverType |= 296 ((primeid & DRI2DriverPrimeMask) << DRI2DriverPrimeShift); 297 } 298 } 299#endif 300 301 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 302 UnlockDisplay(dpy); 303 SyncHandle(); 304 return False; 305 } 306 307 if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) { 308 UnlockDisplay(dpy); 309 SyncHandle(); 310 return False; 311 } 312 313 *driverName = malloc(rep.driverNameLength + 1); 314 if (*driverName == NULL) { 315 _XEatData(dpy, 316 ((rep.driverNameLength + 3) & ~3) + 317 ((rep.deviceNameLength + 3) & ~3)); 318 UnlockDisplay(dpy); 319 SyncHandle(); 320 return False; 321 } 322 _XReadPad(dpy, *driverName, rep.driverNameLength); 323 (*driverName)[rep.driverNameLength] = '\0'; 324 325 *deviceName = malloc(rep.deviceNameLength + 1); 326 if (*deviceName == NULL) { 327 free(*driverName); 328 _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3)); 329 UnlockDisplay(dpy); 330 SyncHandle(); 331 return False; 332 } 333 _XReadPad(dpy, *deviceName, rep.deviceNameLength); 334 (*deviceName)[rep.deviceNameLength] = '\0'; 335 336 UnlockDisplay(dpy); 337 SyncHandle(); 338 339 return True; 340} 341 342Bool 343DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic) 344{ 345 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 346 xDRI2AuthenticateReq *req; 347 xDRI2AuthenticateReply rep; 348 349 XextCheckExtension(dpy, info, dri2ExtensionName, False); 350 351 LockDisplay(dpy); 352 GetReq(DRI2Authenticate, req); 353 req->reqType = info->codes->major_opcode; 354 req->dri2ReqType = X_DRI2Authenticate; 355 req->window = window; 356 req->magic = magic; 357 358 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 359 UnlockDisplay(dpy); 360 SyncHandle(); 361 return False; 362 } 363 364 UnlockDisplay(dpy); 365 SyncHandle(); 366 367 return rep.authenticated; 368} 369 370void 371DRI2CreateDrawable(Display * dpy, XID drawable) 372{ 373 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 374 xDRI2CreateDrawableReq *req; 375 376 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 377 378 LockDisplay(dpy); 379 GetReq(DRI2CreateDrawable, req); 380 req->reqType = info->codes->major_opcode; 381 req->dri2ReqType = X_DRI2CreateDrawable; 382 req->drawable = drawable; 383 UnlockDisplay(dpy); 384 SyncHandle(); 385} 386 387void 388DRI2DestroyDrawable(Display * dpy, XID drawable) 389{ 390 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 391 xDRI2DestroyDrawableReq *req; 392 393 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 394 395 XSync(dpy, False); 396 397 LockDisplay(dpy); 398 GetReq(DRI2DestroyDrawable, req); 399 req->reqType = info->codes->major_opcode; 400 req->dri2ReqType = X_DRI2DestroyDrawable; 401 req->drawable = drawable; 402 UnlockDisplay(dpy); 403 SyncHandle(); 404} 405 406DRI2Buffer * 407DRI2GetBuffers(Display * dpy, XID drawable, 408 int *width, int *height, 409 unsigned int *attachments, int count, int *outCount) 410{ 411 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 412 xDRI2GetBuffersReply rep; 413 xDRI2GetBuffersReq *req; 414 DRI2Buffer *buffers; 415 xDRI2Buffer repBuffer; 416 CARD32 *p; 417 int i; 418 419 XextCheckExtension(dpy, info, dri2ExtensionName, False); 420 421 LockDisplay(dpy); 422 GetReqExtra(DRI2GetBuffers, count * 4, req); 423 req->reqType = info->codes->major_opcode; 424 req->dri2ReqType = X_DRI2GetBuffers; 425 req->drawable = drawable; 426 req->count = count; 427 p = (CARD32 *) & req[1]; 428 for (i = 0; i < count; i++) 429 p[i] = attachments[i]; 430 431 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 432 UnlockDisplay(dpy); 433 SyncHandle(); 434 return NULL; 435 } 436 437 *width = rep.width; 438 *height = rep.height; 439 *outCount = rep.count; 440 441 buffers = malloc(rep.count * sizeof buffers[0]); 442 if (buffers == NULL) { 443 _XEatData(dpy, rep.count * sizeof repBuffer); 444 UnlockDisplay(dpy); 445 SyncHandle(); 446 return NULL; 447 } 448 449 for (i = 0; i < rep.count; i++) { 450 _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); 451 buffers[i].attachment = repBuffer.attachment; 452 buffers[i].name = repBuffer.name; 453 buffers[i].pitch = repBuffer.pitch; 454 buffers[i].cpp = repBuffer.cpp; 455 buffers[i].flags = repBuffer.flags; 456 } 457 458 UnlockDisplay(dpy); 459 SyncHandle(); 460 461 return buffers; 462} 463 464 465DRI2Buffer * 466DRI2GetBuffersWithFormat(Display * dpy, XID drawable, 467 int *width, int *height, 468 unsigned int *attachments, int count, int *outCount) 469{ 470 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 471 xDRI2GetBuffersReply rep; 472 xDRI2GetBuffersReq *req; 473 DRI2Buffer *buffers; 474 xDRI2Buffer repBuffer; 475 CARD32 *p; 476 int i; 477 478 XextCheckExtension(dpy, info, dri2ExtensionName, False); 479 480 LockDisplay(dpy); 481 GetReqExtra(DRI2GetBuffers, count * (4 * 2), req); 482 req->reqType = info->codes->major_opcode; 483 req->dri2ReqType = X_DRI2GetBuffersWithFormat; 484 req->drawable = drawable; 485 req->count = count; 486 p = (CARD32 *) & req[1]; 487 for (i = 0; i < (count * 2); i++) 488 p[i] = attachments[i]; 489 490 if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 491 UnlockDisplay(dpy); 492 SyncHandle(); 493 return NULL; 494 } 495 496 *width = rep.width; 497 *height = rep.height; 498 *outCount = rep.count; 499 500 buffers = malloc(rep.count * sizeof buffers[0]); 501 if (buffers == NULL) { 502 _XEatData(dpy, rep.count * sizeof repBuffer); 503 UnlockDisplay(dpy); 504 SyncHandle(); 505 return NULL; 506 } 507 508 for (i = 0; i < rep.count; i++) { 509 _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); 510 buffers[i].attachment = repBuffer.attachment; 511 buffers[i].name = repBuffer.name; 512 buffers[i].pitch = repBuffer.pitch; 513 buffers[i].cpp = repBuffer.cpp; 514 buffers[i].flags = repBuffer.flags; 515 } 516 517 UnlockDisplay(dpy); 518 SyncHandle(); 519 520 return buffers; 521} 522 523 524void 525DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region, 526 CARD32 dest, CARD32 src) 527{ 528 XExtDisplayInfo *info = DRI2FindDisplay(dpy); 529 xDRI2CopyRegionReq *req; 530 xDRI2CopyRegionReply rep; 531 532 XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 533 534 LockDisplay(dpy); 535 GetReq(DRI2CopyRegion, req); 536 req->reqType = info->codes->major_opcode; 537 req->dri2ReqType = X_DRI2CopyRegion; 538 req->drawable = drawable; 539 req->region = region; 540 req->dest = dest; 541 req->src = src; 542 543 _XReply(dpy, (xReply *) & rep, 0, xFalse); 544 545 UnlockDisplay(dpy); 546 SyncHandle(); 547} 548 549#endif /* GLX_DIRECT_RENDERING */ 550