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