xf86dri.c revision 05b261ec
1/************************************************************************** 2 3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 4Copyright 2000 VA Linux Systems, Inc. 5All Rights Reserved. 6 7Permission is hereby granted, free of charge, to any person obtaining a 8copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sub license, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice (including the 16next paragraph) shall be included in all copies or substantial portions 17of the Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 27**************************************************************************/ 28 29/* 30 * Authors: 31 * Kevin E. Martin <martin@valinux.com> 32 * Jens Owen <jens@tungstengraphics.com> 33 * Rickard E. (Rik) Faith <faith@valinux.com> 34 * 35 */ 36 37#ifdef HAVE_XORG_CONFIG_H 38#include <xorg-config.h> 39#endif 40 41#include <string.h> 42 43#include "xf86.h" 44 45#define NEED_REPLIES 46#define NEED_EVENTS 47#include <X11/X.h> 48#include <X11/Xproto.h> 49#include "misc.h" 50#include "dixstruct.h" 51#include "extnsionst.h" 52#include "colormapst.h" 53#include "cursorstr.h" 54#include "scrnintstr.h" 55#include "servermd.h" 56#define _XF86DRI_SERVER_ 57#include "xf86dristr.h" 58#include "swaprep.h" 59#include "xf86str.h" 60#include "dri.h" 61#include "sarea.h" 62#include "dristruct.h" 63#include "xf86.h" 64#include "xf86drm.h" 65 66static int DRIErrorBase; 67 68static DISPATCH_PROC(ProcXF86DRIQueryVersion); 69static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable); 70static DISPATCH_PROC(ProcXF86DRIOpenConnection); 71static DISPATCH_PROC(ProcXF86DRICloseConnection); 72static DISPATCH_PROC(ProcXF86DRIGetClientDriverName); 73static DISPATCH_PROC(ProcXF86DRICreateContext); 74static DISPATCH_PROC(ProcXF86DRIDestroyContext); 75static DISPATCH_PROC(ProcXF86DRICreateDrawable); 76static DISPATCH_PROC(ProcXF86DRIDestroyDrawable); 77static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo); 78static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo); 79static DISPATCH_PROC(ProcXF86DRIDispatch); 80static DISPATCH_PROC(ProcXF86DRIAuthConnection); 81 82static DISPATCH_PROC(SProcXF86DRIQueryVersion); 83static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable); 84static DISPATCH_PROC(SProcXF86DRIDispatch); 85 86static void XF86DRIResetProc(ExtensionEntry* extEntry); 87 88static unsigned char DRIReqCode = 0; 89 90extern void XFree86DRIExtensionInit(void); 91 92void 93XFree86DRIExtensionInit(void) 94{ 95 ExtensionEntry* extEntry; 96 97#ifdef XF86DRI_EVENTS 98 EventType = CreateNewResourceType(XF86DRIFreeEvents); 99#endif 100 101 if ( 102 DRIExtensionInit() && 103#ifdef XF86DRI_EVENTS 104 EventType && ScreenPrivateIndex != -1 && 105#endif 106 (extEntry = AddExtension(XF86DRINAME, 107 XF86DRINumberEvents, 108 XF86DRINumberErrors, 109 ProcXF86DRIDispatch, 110 SProcXF86DRIDispatch, 111 XF86DRIResetProc, 112 StandardMinorOpcode))) { 113 DRIReqCode = (unsigned char)extEntry->base; 114 DRIErrorBase = extEntry->errorBase; 115 } 116} 117 118/*ARGSUSED*/ 119static void 120XF86DRIResetProc ( 121 ExtensionEntry* extEntry 122) 123{ 124 DRIReset(); 125} 126 127static int 128ProcXF86DRIQueryVersion( 129 register ClientPtr client 130) 131{ 132 xXF86DRIQueryVersionReply rep; 133 register int n; 134 135 REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); 136 rep.type = X_Reply; 137 rep.length = 0; 138 rep.sequenceNumber = client->sequence; 139 rep.majorVersion = XF86DRI_MAJOR_VERSION; 140 rep.minorVersion = XF86DRI_MINOR_VERSION; 141 rep.patchVersion = XF86DRI_PATCH_VERSION; 142 if (client->swapped) { 143 swaps(&rep.sequenceNumber, n); 144 swapl(&rep.length, n); 145 swaps(&rep.majorVersion, n); 146 swaps(&rep.minorVersion, n); 147 swapl(&rep.patchVersion, n); 148 } 149 WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); 150 return (client->noClientException); 151} 152 153static int 154ProcXF86DRIQueryDirectRenderingCapable( 155 register ClientPtr client 156) 157{ 158 xXF86DRIQueryDirectRenderingCapableReply rep; 159 Bool isCapable; 160 register int n; 161 162 REQUEST(xXF86DRIQueryDirectRenderingCapableReq); 163 REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); 164 if (stuff->screen >= screenInfo.numScreens) { 165 client->errorValue = stuff->screen; 166 return BadValue; 167 } 168 169 rep.type = X_Reply; 170 rep.length = 0; 171 rep.sequenceNumber = client->sequence; 172 173 if (!DRIQueryDirectRenderingCapable( screenInfo.screens[stuff->screen], 174 &isCapable)) { 175 return BadValue; 176 } 177 rep.isCapable = isCapable; 178 179 if (!LocalClient(client) || client->swapped) 180 rep.isCapable = 0; 181 182 if (client->swapped) { 183 swaps(&rep.sequenceNumber, n); 184 swapl(&rep.length, n); 185 } 186 187 WriteToClient(client, 188 sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); 189 return (client->noClientException); 190} 191 192static int 193ProcXF86DRIOpenConnection( 194 register ClientPtr client 195) 196{ 197 xXF86DRIOpenConnectionReply rep; 198 drm_handle_t hSAREA; 199 char* busIdString; 200 201 REQUEST(xXF86DRIOpenConnectionReq); 202 REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); 203 if (stuff->screen >= screenInfo.numScreens) { 204 client->errorValue = stuff->screen; 205 return BadValue; 206 } 207 208 if (!DRIOpenConnection( screenInfo.screens[stuff->screen], 209 &hSAREA, 210 &busIdString)) { 211 return BadValue; 212 } 213 214 rep.type = X_Reply; 215 rep.sequenceNumber = client->sequence; 216 rep.busIdStringLength = 0; 217 if (busIdString) 218 rep.busIdStringLength = strlen(busIdString); 219 rep.length = (SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + 220 ((rep.busIdStringLength + 3) & ~3)) >> 2; 221 222 rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff); 223#if defined(LONG64) && !defined(__linux__) 224 rep.hSAREAHigh = (CARD32)(hSAREA >> 32); 225#else 226 rep.hSAREAHigh = 0; 227#endif 228 229 WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep); 230 if (rep.busIdStringLength) 231 WriteToClient(client, rep.busIdStringLength, busIdString); 232 return (client->noClientException); 233} 234 235static int 236ProcXF86DRIAuthConnection( 237 register ClientPtr client 238) 239{ 240 xXF86DRIAuthConnectionReply rep; 241 242 REQUEST(xXF86DRIAuthConnectionReq); 243 REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); 244 if (stuff->screen >= screenInfo.numScreens) { 245 client->errorValue = stuff->screen; 246 return BadValue; 247 } 248 249 rep.type = X_Reply; 250 rep.length = 0; 251 rep.sequenceNumber = client->sequence; 252 rep.authenticated = 1; 253 254 if (!DRIAuthConnection( screenInfo.screens[stuff->screen], stuff->magic)) { 255 ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic); 256 rep.authenticated = 0; 257 } 258 WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep); 259 return (client->noClientException); 260} 261 262static int 263ProcXF86DRICloseConnection( 264 register ClientPtr client 265) 266{ 267 REQUEST(xXF86DRICloseConnectionReq); 268 REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); 269 if (stuff->screen >= screenInfo.numScreens) { 270 client->errorValue = stuff->screen; 271 return BadValue; 272 } 273 274 DRICloseConnection( screenInfo.screens[stuff->screen]); 275 276 return (client->noClientException); 277} 278 279static int 280ProcXF86DRIGetClientDriverName( 281 register ClientPtr client 282) 283{ 284 xXF86DRIGetClientDriverNameReply rep; 285 char* clientDriverName; 286 287 REQUEST(xXF86DRIGetClientDriverNameReq); 288 REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); 289 if (stuff->screen >= screenInfo.numScreens) { 290 client->errorValue = stuff->screen; 291 return BadValue; 292 } 293 294 DRIGetClientDriverName( screenInfo.screens[stuff->screen], 295 (int *)&rep.ddxDriverMajorVersion, 296 (int *)&rep.ddxDriverMinorVersion, 297 (int *)&rep.ddxDriverPatchVersion, 298 &clientDriverName); 299 300 rep.type = X_Reply; 301 rep.sequenceNumber = client->sequence; 302 rep.clientDriverNameLength = 0; 303 if (clientDriverName) 304 rep.clientDriverNameLength = strlen(clientDriverName); 305 rep.length = (SIZEOF(xXF86DRIGetClientDriverNameReply) - 306 SIZEOF(xGenericReply) + 307 ((rep.clientDriverNameLength + 3) & ~3)) >> 2; 308 309 WriteToClient(client, 310 sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); 311 if (rep.clientDriverNameLength) 312 WriteToClient(client, 313 rep.clientDriverNameLength, 314 clientDriverName); 315 return (client->noClientException); 316} 317 318static int 319ProcXF86DRICreateContext( 320 register ClientPtr client 321) 322{ 323 xXF86DRICreateContextReply rep; 324 ScreenPtr pScreen; 325 VisualPtr visual; 326 int i; 327 328 REQUEST(xXF86DRICreateContextReq); 329 REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); 330 if (stuff->screen >= screenInfo.numScreens) { 331 client->errorValue = stuff->screen; 332 return BadValue; 333 } 334 335 rep.type = X_Reply; 336 rep.length = 0; 337 rep.sequenceNumber = client->sequence; 338 339 pScreen = screenInfo.screens[stuff->screen]; 340 visual = pScreen->visuals; 341 342 /* Find the requested X visual */ 343 for (i = 0; i < pScreen->numVisuals; i++, visual++) 344 if (visual->vid == stuff->visual) 345 break; 346 if (i == pScreen->numVisuals) { 347 /* No visual found */ 348 return BadValue; 349 } 350 351 if (!DRICreateContext( pScreen, 352 visual, 353 stuff->context, 354 (drm_context_t *)&rep.hHWContext)) { 355 return BadValue; 356 } 357 358 WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); 359 return (client->noClientException); 360} 361 362static int 363ProcXF86DRIDestroyContext( 364 register ClientPtr client 365) 366{ 367 REQUEST(xXF86DRIDestroyContextReq); 368 REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); 369 if (stuff->screen >= screenInfo.numScreens) { 370 client->errorValue = stuff->screen; 371 return BadValue; 372 } 373 374 if (!DRIDestroyContext( screenInfo.screens[stuff->screen], 375 stuff->context)) { 376 return BadValue; 377 } 378 379 return (client->noClientException); 380} 381 382static int 383ProcXF86DRICreateDrawable( 384 ClientPtr client 385) 386{ 387 xXF86DRICreateDrawableReply rep; 388 DrawablePtr pDrawable; 389 int rc; 390 391 REQUEST(xXF86DRICreateDrawableReq); 392 REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); 393 if (stuff->screen >= screenInfo.numScreens) { 394 client->errorValue = stuff->screen; 395 return BadValue; 396 } 397 398 rep.type = X_Reply; 399 rep.length = 0; 400 rep.sequenceNumber = client->sequence; 401 402 rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, 403 DixReadAccess); 404 if (rc != Success) 405 return rc; 406 407 if (!DRICreateDrawable(screenInfo.screens[stuff->screen], client, 408 pDrawable, (drm_drawable_t *)&rep.hHWDrawable)) { 409 return BadValue; 410 } 411 412 WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); 413 return (client->noClientException); 414} 415 416static int 417ProcXF86DRIDestroyDrawable( 418 register ClientPtr client 419) 420{ 421 REQUEST(xXF86DRIDestroyDrawableReq); 422 DrawablePtr pDrawable; 423 REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); 424 int rc; 425 426 if (stuff->screen >= screenInfo.numScreens) { 427 client->errorValue = stuff->screen; 428 return BadValue; 429 } 430 431 rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, 432 DixReadAccess); 433 if (rc != Success) 434 return rc; 435 436 if (!DRIDestroyDrawable(screenInfo.screens[stuff->screen], client, 437 pDrawable)) { 438 return BadValue; 439 } 440 441 return (client->noClientException); 442} 443 444static int 445ProcXF86DRIGetDrawableInfo( 446 register ClientPtr client 447) 448{ 449 xXF86DRIGetDrawableInfoReply rep; 450 DrawablePtr pDrawable; 451 int X, Y, W, H; 452 drm_clip_rect_t * pClipRects, *pClippedRects; 453 drm_clip_rect_t * pBackClipRects; 454 int backX, backY, rc; 455 456 REQUEST(xXF86DRIGetDrawableInfoReq); 457 REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); 458 if (stuff->screen >= screenInfo.numScreens) { 459 client->errorValue = stuff->screen; 460 return BadValue; 461 } 462 463 rep.type = X_Reply; 464 rep.length = 0; 465 rep.sequenceNumber = client->sequence; 466 467 rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, 468 DixReadAccess); 469 if (rc != Success) 470 return rc; 471 472 if (!DRIGetDrawableInfo( screenInfo.screens[stuff->screen], 473 pDrawable, 474 (unsigned int*)&rep.drawableTableIndex, 475 (unsigned int*)&rep.drawableTableStamp, 476 (int*)&X, 477 (int*)&Y, 478 (int*)&W, 479 (int*)&H, 480 (int*)&rep.numClipRects, 481 &pClipRects, 482 &backX, 483 &backY, 484 (int*)&rep.numBackClipRects, 485 &pBackClipRects)) { 486 return BadValue; 487 } 488 489 rep.drawableX = X; 490 rep.drawableY = Y; 491 rep.drawableWidth = W; 492 rep.drawableHeight = H; 493 rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) - 494 SIZEOF(xGenericReply)); 495 496 rep.backX = backX; 497 rep.backY = backY; 498 499 if (rep.numBackClipRects) 500 rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; 501 502 pClippedRects = pClipRects; 503 504 if (rep.numClipRects) { 505 /* Clip cliprects to screen dimensions (redirected windows) */ 506 pClippedRects = xalloc(rep.numClipRects * sizeof(drm_clip_rect_t)); 507 508 if (pClippedRects) { 509 ScreenPtr pScreen = screenInfo.screens[stuff->screen]; 510 int i, j; 511 512 for (i = 0, j = 0; i < rep.numClipRects; i++) { 513 pClippedRects[j].x1 = max(pClipRects[i].x1, 0); 514 pClippedRects[j].y1 = max(pClipRects[i].y1, 0); 515 pClippedRects[j].x2 = min(pClipRects[i].x2, pScreen->width); 516 pClippedRects[j].y2 = min(pClipRects[i].y2, pScreen->height); 517 518 if (pClippedRects[j].x1 < pClippedRects[j].x2 && 519 pClippedRects[j].y1 < pClippedRects[j].y2) { 520 j++; 521 } 522 } 523 524 rep.numClipRects = j; 525 } else { 526 rep.numClipRects = 0; 527 } 528 529 rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; 530 } 531 532 rep.length = ((rep.length + 3) & ~3) >> 2; 533 534 WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); 535 536 if (rep.numClipRects) { 537 WriteToClient(client, 538 sizeof(drm_clip_rect_t) * rep.numClipRects, 539 (char *)pClippedRects); 540 xfree(pClippedRects); 541 } 542 543 if (rep.numBackClipRects) { 544 WriteToClient(client, 545 sizeof(drm_clip_rect_t) * rep.numBackClipRects, 546 (char *)pBackClipRects); 547 } 548 549 return (client->noClientException); 550} 551 552static int 553ProcXF86DRIGetDeviceInfo( 554 register ClientPtr client 555) 556{ 557 xXF86DRIGetDeviceInfoReply rep; 558 drm_handle_t hFrameBuffer; 559 void *pDevPrivate; 560 561 REQUEST(xXF86DRIGetDeviceInfoReq); 562 REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); 563 if (stuff->screen >= screenInfo.numScreens) { 564 client->errorValue = stuff->screen; 565 return BadValue; 566 } 567 568 rep.type = X_Reply; 569 rep.length = 0; 570 rep.sequenceNumber = client->sequence; 571 572 if (!DRIGetDeviceInfo( screenInfo.screens[stuff->screen], 573 &hFrameBuffer, 574 (int*)&rep.framebufferOrigin, 575 (int*)&rep.framebufferSize, 576 (int*)&rep.framebufferStride, 577 (int*)&rep.devPrivateSize, 578 &pDevPrivate)) { 579 return BadValue; 580 } 581 582 rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff); 583#if defined(LONG64) && !defined(__linux__) 584 rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32); 585#else 586 rep.hFrameBufferHigh = 0; 587#endif 588 589 rep.length = 0; 590 if (rep.devPrivateSize) { 591 rep.length = (SIZEOF(xXF86DRIGetDeviceInfoReply) - 592 SIZEOF(xGenericReply) + 593 ((rep.devPrivateSize + 3) & ~3)) >> 2; 594 } 595 596 WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); 597 if (rep.length) { 598 WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); 599 } 600 return (client->noClientException); 601} 602 603static int 604ProcXF86DRIDispatch ( 605 register ClientPtr client 606) 607{ 608 REQUEST(xReq); 609 610 switch (stuff->data) 611 { 612 case X_XF86DRIQueryVersion: 613 return ProcXF86DRIQueryVersion(client); 614 case X_XF86DRIQueryDirectRenderingCapable: 615 return ProcXF86DRIQueryDirectRenderingCapable(client); 616 } 617 618 if (!LocalClient(client)) 619 return DRIErrorBase + XF86DRIClientNotLocal; 620 621 switch (stuff->data) 622 { 623 case X_XF86DRIOpenConnection: 624 return ProcXF86DRIOpenConnection(client); 625 case X_XF86DRICloseConnection: 626 return ProcXF86DRICloseConnection(client); 627 case X_XF86DRIGetClientDriverName: 628 return ProcXF86DRIGetClientDriverName(client); 629 case X_XF86DRICreateContext: 630 return ProcXF86DRICreateContext(client); 631 case X_XF86DRIDestroyContext: 632 return ProcXF86DRIDestroyContext(client); 633 case X_XF86DRICreateDrawable: 634 return ProcXF86DRICreateDrawable(client); 635 case X_XF86DRIDestroyDrawable: 636 return ProcXF86DRIDestroyDrawable(client); 637 case X_XF86DRIGetDrawableInfo: 638 return ProcXF86DRIGetDrawableInfo(client); 639 case X_XF86DRIGetDeviceInfo: 640 return ProcXF86DRIGetDeviceInfo(client); 641 case X_XF86DRIAuthConnection: 642 return ProcXF86DRIAuthConnection(client); 643 /* {Open,Close}FullScreen are deprecated now */ 644 default: 645 return BadRequest; 646 } 647} 648 649static int 650SProcXF86DRIQueryVersion( 651 register ClientPtr client 652) 653{ 654 register int n; 655 REQUEST(xXF86DRIQueryVersionReq); 656 swaps(&stuff->length, n); 657 return ProcXF86DRIQueryVersion(client); 658} 659 660static int 661SProcXF86DRIQueryDirectRenderingCapable( 662 register ClientPtr client 663) 664{ 665 register int n; 666 REQUEST(xXF86DRIQueryDirectRenderingCapableReq); 667 swaps(&stuff->length, n); 668 swapl(&stuff->screen, n); 669 return ProcXF86DRIQueryDirectRenderingCapable(client); 670} 671 672static int 673SProcXF86DRIDispatch ( 674 register ClientPtr client 675) 676{ 677 REQUEST(xReq); 678 679 /* 680 * Only local clients are allowed DRI access, but remote clients still need 681 * these requests to find out cleanly. 682 */ 683 switch (stuff->data) 684 { 685 case X_XF86DRIQueryVersion: 686 return SProcXF86DRIQueryVersion(client); 687 case X_XF86DRIQueryDirectRenderingCapable: 688 return SProcXF86DRIQueryDirectRenderingCapable(client); 689 default: 690 return DRIErrorBase + XF86DRIClientNotLocal; 691 } 692} 693