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