glxdri.c revision 706f2543
1/* 2 * Copyright © 2006 Red Hat, Inc 3 * 4 * Permission to use, copy, modify, distribute, and sell this software 5 * and its documentation for any purpose is hereby granted without 6 * fee, provided that the above copyright notice appear in all copies 7 * and that both that copyright notice and this permission notice 8 * appear in supporting documentation, and that the name of Red Hat, 9 * Inc not be used in advertising or publicity pertaining to 10 * distribution of the software without specific, written prior 11 * permission. Red Hat, Inc makes no representations about the 12 * suitability of this software for any purpose. It is provided "as 13 * is" without express or implied warranty. 14 * 15 * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 17 * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_DIX_CONFIG_H 25#include <dix-config.h> 26#endif 27 28#include <stdint.h> 29#include <stdio.h> 30#include <string.h> 31#include <errno.h> 32#include <sys/time.h> 33#include <dlfcn.h> 34 35#include <drm.h> 36#include <GL/gl.h> 37#include <GL/internal/dri_interface.h> 38#include <GL/glxtokens.h> 39 40#include <windowstr.h> 41#include <os.h> 42#include <damage.h> 43 44#define _XF86DRI_SERVER_ 45#include <drm_sarea.h> 46#include <xf86drm.h> 47#include <X11/dri/xf86driproto.h> 48#include <xf86str.h> 49#include <xf86.h> 50#include <dri.h> 51 52#include "servermd.h" 53 54#define DRI_NEW_INTERFACE_ONLY 55#include "glxserver.h" 56#include "glxutil.h" 57#include "glxdricommon.h" 58 59#include "glapitable.h" 60#include "glapi.h" 61#include "glthread.h" 62#include "dispatch.h" 63#include "extension_string.h" 64 65typedef struct __GLXDRIscreen __GLXDRIscreen; 66typedef struct __GLXDRIcontext __GLXDRIcontext; 67typedef struct __GLXDRIdrawable __GLXDRIdrawable; 68 69struct __GLXDRIscreen { 70 __GLXscreen base; 71 __DRIscreen *driScreen; 72 void *driver; 73 74 xf86EnterVTProc *enterVT; 75 xf86LeaveVTProc *leaveVT; 76 77 const __DRIcoreExtension *core; 78 const __DRIlegacyExtension *legacy; 79 const __DRIcopySubBufferExtension *copySubBuffer; 80 const __DRIswapControlExtension *swapControl; 81 82#ifdef __DRI_TEX_OFFSET 83 const __DRItexOffsetExtension *texOffset; 84 DRITexOffsetStartProcPtr texOffsetStart; 85 DRITexOffsetFinishProcPtr texOffsetFinish; 86 __GLXDRIdrawable *texOffsetOverride[16]; 87 GLuint lastTexOffsetOverride; 88#endif 89 90 unsigned char glx_enable_bits[__GLX_EXT_BYTES]; 91}; 92 93struct __GLXDRIcontext { 94 __GLXcontext base; 95 __DRIcontext *driContext; 96 XID hwContextID; 97}; 98 99struct __GLXDRIdrawable { 100 __GLXdrawable base; 101 __DRIdrawable *driDrawable; 102 103 /* Pulled in from old __GLXpixmap */ 104#ifdef __DRI_TEX_OFFSET 105 GLint texname; 106 __GLXDRIcontext *ctx; 107 unsigned long long offset; 108 DamagePtr pDamage; 109#endif 110}; 111 112static void 113__glXDRIleaveServer(GLboolean rendering) 114{ 115 int i; 116 117 for (i = 0; rendering && i < screenInfo.numScreens; i++) { 118 __GLXDRIscreen * const screen = 119 (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]); 120 GLuint lastOverride = screen->lastTexOffsetOverride; 121 122 if (lastOverride) { 123 __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride; 124 int j; 125 126 for (j = 0; j < lastOverride; j++) { 127 __GLXDRIdrawable *pGlxPix = texOffsetOverride[j]; 128 129 if (pGlxPix && pGlxPix->texname) { 130 pGlxPix->offset = 131 screen->texOffsetStart((PixmapPtr)pGlxPix->base.pDraw); 132 } 133 } 134 } 135 } 136 137 DRIBlockHandler(NULL, NULL, NULL); 138 139 for (i = 0; rendering && i < screenInfo.numScreens; i++) { 140 __GLXDRIscreen * const screen = 141 (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]); 142 GLuint lastOverride = screen->lastTexOffsetOverride; 143 144 if (lastOverride) { 145 __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride; 146 int j; 147 148 for (j = 0; j < lastOverride; j++) { 149 __GLXDRIdrawable *pGlxPix = texOffsetOverride[j]; 150 151 if (pGlxPix && pGlxPix->texname) { 152 screen->texOffset->setTexOffset(pGlxPix->ctx->driContext, 153 pGlxPix->texname, 154 pGlxPix->offset, 155 pGlxPix->base.pDraw->depth, 156 ((PixmapPtr)pGlxPix->base.pDraw)->devKind); 157 } 158 } 159 } 160 } 161} 162 163static void 164__glXDRIenterServer(GLboolean rendering) 165{ 166 int i; 167 168 for (i = 0; rendering && i < screenInfo.numScreens; i++) { 169 __GLXDRIscreen * const screen = (__GLXDRIscreen *) 170 glxGetScreen(screenInfo.screens[i]); 171 172 if (screen->lastTexOffsetOverride) { 173 CALL_Flush(GET_DISPATCH(), ()); 174 break; 175 } 176 } 177 178 DRIWakeupHandler(NULL, 0, NULL); 179} 180 181 182static void 183__glXDRIdoReleaseTexImage(__GLXDRIscreen *screen, __GLXDRIdrawable *drawable) 184{ 185 GLuint lastOverride = screen->lastTexOffsetOverride; 186 187 if (lastOverride) { 188 __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride; 189 int i; 190 191 for (i = 0; i < lastOverride; i++) { 192 if (texOffsetOverride[i] == drawable) { 193 if (screen->texOffsetFinish) 194 screen->texOffsetFinish((PixmapPtr)drawable->base.pDraw); 195 196 texOffsetOverride[i] = NULL; 197 198 if (i + 1 == lastOverride) { 199 lastOverride = 0; 200 201 while (i--) { 202 if (texOffsetOverride[i]) { 203 lastOverride = i + 1; 204 break; 205 } 206 } 207 208 screen->lastTexOffsetOverride = lastOverride; 209 210 break; 211 } 212 } 213 } 214 } 215} 216 217 218static void 219__glXDRIdrawableDestroy(__GLXdrawable *drawable) 220{ 221 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 222 __GLXDRIscreen *screen; 223 int i; 224 225 for (i = 0; i < screenInfo.numScreens; i++) { 226 screen = (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]); 227 __glXDRIdoReleaseTexImage(screen, private); 228 } 229 230 /* If the X window was destroyed, the dri DestroyWindow hook will 231 * aready have taken care of this, so only call if pDraw isn't NULL. */ 232 if (drawable->pDraw != NULL) { 233 screen = (__GLXDRIscreen *) glxGetScreen(drawable->pDraw->pScreen); 234 (*screen->core->destroyDrawable)(private->driDrawable); 235 236 __glXenterServer(GL_FALSE); 237 DRIDestroyDrawable(drawable->pDraw->pScreen, 238 serverClient, drawable->pDraw); 239 __glXleaveServer(GL_FALSE); 240 } 241 242 __glXDrawableRelease(drawable); 243 244 free(private); 245} 246 247static GLboolean 248__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *basePrivate) 249{ 250 __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; 251 __GLXDRIscreen *screen = 252 (__GLXDRIscreen *) glxGetScreen(basePrivate->pDraw->pScreen); 253 254 (*screen->core->swapBuffers)(private->driDrawable); 255 256 return TRUE; 257} 258 259 260static int 261__glXDRIdrawableSwapInterval(__GLXdrawable *baseDrawable, int interval) 262{ 263 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseDrawable; 264 __GLXDRIscreen *screen = 265 (__GLXDRIscreen *) glxGetScreen(baseDrawable->pDraw->pScreen); 266 267 if (screen->swapControl) 268 screen->swapControl->setSwapInterval(draw->driDrawable, interval); 269 270 return 0; 271} 272 273 274static void 275__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate, 276 int x, int y, int w, int h) 277{ 278 __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; 279 __GLXDRIscreen *screen = (__GLXDRIscreen *) 280 glxGetScreen(basePrivate->pDraw->pScreen); 281 282 if (screen->copySubBuffer) 283 screen->copySubBuffer->copySubBuffer(private->driDrawable, x, y, w, h); 284} 285 286static void 287__glXDRIcontextDestroy(__GLXcontext *baseContext) 288{ 289 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 290 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 291 Bool retval; 292 293 screen->core->destroyContext(context->driContext); 294 295 __glXenterServer(GL_FALSE); 296 retval = DRIDestroyContext(baseContext->pGlxScreen->pScreen, 297 context->hwContextID); 298 __glXleaveServer(GL_FALSE); 299 300 __glXContextDestroy(&context->base); 301 free(context); 302} 303 304static int 305__glXDRIcontextMakeCurrent(__GLXcontext *baseContext) 306{ 307 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 308 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 309 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 310 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 311 312 return (*screen->core->bindContext)(context->driContext, 313 draw->driDrawable, 314 read->driDrawable); 315} 316 317static int 318__glXDRIcontextLoseCurrent(__GLXcontext *baseContext) 319{ 320 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 321 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 322 323 return (*screen->core->unbindContext)(context->driContext); 324} 325 326static int 327__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, 328 unsigned long mask) 329{ 330 __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; 331 __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; 332 __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; 333 334 return (*screen->core->copyContext)(dst->driContext, 335 src->driContext, mask); 336} 337 338static int 339__glXDRIcontextForceCurrent(__GLXcontext *baseContext) 340{ 341 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 342 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 343 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 344 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 345 346 return (*screen->core->bindContext)(context->driContext, 347 draw->driDrawable, 348 read->driDrawable); 349} 350 351static void 352glxFillAlphaChannel (CARD32 *pixels, CARD32 rowstride, int width, int height) 353{ 354 int i; 355 CARD32 *p, *end; 356 357 rowstride /= 4; 358 359 for (i = 0; i < height; i++) 360 { 361 p = pixels; 362 end = p + width; 363 while (p < end) 364 *p++ |= 0xFF000000; 365 pixels += rowstride; 366 } 367} 368 369static Bool 370testTexOffset(__GLXDRIscreen * const screen, PixmapPtr pPixmap) 371{ 372 Bool ret; 373 374 if (!screen->texOffsetStart || !screen->texOffset) 375 return FALSE; 376 377 __glXenterServer(GL_FALSE); 378 ret = screen->texOffsetStart(pPixmap) != ~0ULL; 379 __glXleaveServer(GL_FALSE); 380 381 return ret; 382} 383 384/* 385 * (sticking this here for lack of a better place) 386 * Known issues with the GLX_EXT_texture_from_pixmap implementation: 387 * - In general we ignore the fbconfig, lots of examples follow 388 * - No fbconfig handling for multiple mipmap levels 389 * - No fbconfig handling for 1D textures 390 * - No fbconfig handling for TEXTURE_TARGET 391 * - No fbconfig exposure of Y inversion state 392 * - No GenerateMipmapEXT support (due to no FBO support) 393 * - No support for anything but 16bpp and 32bpp-sparse pixmaps 394 */ 395 396static int 397__glXDRIbindTexImage(__GLXcontext *baseContext, 398 int buffer, 399 __GLXdrawable *glxPixmap) 400{ 401 RegionPtr pRegion = NULL; 402 PixmapPtr pixmap; 403 int bpp, override = 0, texname; 404 GLenum format, type; 405 ScreenPtr pScreen = glxPixmap->pDraw->pScreen; 406 __GLXDRIdrawable *driDraw = (__GLXDRIdrawable *) glxPixmap; 407 __GLXDRIscreen * const screen = (__GLXDRIscreen *) glxGetScreen(pScreen); 408 409 CALL_GetIntegerv(GET_DISPATCH(), (glxPixmap->target == GL_TEXTURE_2D ? 410 GL_TEXTURE_BINDING_2D : 411 GL_TEXTURE_BINDING_RECTANGLE_NV, 412 &texname)); 413 414 if (!texname) 415 return __glXError(GLXBadContextState); 416 417 pixmap = (PixmapPtr) glxPixmap->pDraw; 418 419 if (testTexOffset(screen, pixmap)) { 420 __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride; 421 int i, firstEmpty = 16; 422 423 for (i = 0; i < 16; i++) { 424 if (texOffsetOverride[i] == driDraw) 425 goto alreadyin; 426 427 if (firstEmpty == 16 && !texOffsetOverride[i]) 428 firstEmpty = i; 429 } 430 431 if (firstEmpty == 16) { 432 ErrorF("%s: Failed to register texture offset override\n", __func__); 433 goto nooverride; 434 } 435 436 if (firstEmpty >= screen->lastTexOffsetOverride) 437 screen->lastTexOffsetOverride = firstEmpty + 1; 438 439 texOffsetOverride[firstEmpty] = driDraw; 440 441alreadyin: 442 override = 1; 443 444 driDraw->ctx = (__GLXDRIcontext*)baseContext; 445 446 if (texname == driDraw->texname) 447 return Success; 448 449 driDraw->texname = texname; 450 451 screen->texOffset->setTexOffset(driDraw->ctx->driContext, texname, 0, 452 pixmap->drawable.depth, 453 pixmap->devKind); 454 } 455nooverride: 456 457 if (!driDraw->pDamage) { 458 if (!override) { 459 driDraw->pDamage = DamageCreate(NULL, NULL, DamageReportNone, 460 TRUE, pScreen, NULL); 461 if (!driDraw->pDamage) 462 return BadAlloc; 463 464 DamageRegister ((DrawablePtr) pixmap, driDraw->pDamage); 465 } 466 467 pRegion = NULL; 468 } else { 469 pRegion = DamageRegion(driDraw->pDamage); 470 if (RegionNil(pRegion)) 471 return Success; 472 } 473 474 /* XXX 24bpp packed, 8, etc */ 475 if (pixmap->drawable.depth >= 24) { 476 bpp = 4; 477 format = GL_BGRA; 478 type = 479#if X_BYTE_ORDER == X_BIG_ENDIAN 480 !override ? GL_UNSIGNED_INT_8_8_8_8_REV : 481#endif 482 GL_UNSIGNED_BYTE; 483 } else { 484 bpp = 2; 485 format = GL_RGB; 486 type = GL_UNSIGNED_SHORT_5_6_5; 487 } 488 489 if (pRegion == NULL) 490 { 491 void *data = NULL; 492 493 if (!override) { 494 unsigned pitch = PixmapBytePad(pixmap->drawable.width, 495 pixmap->drawable.depth); 496 497 data = malloc(pitch * pixmap->drawable.height); 498 499 __glXenterServer(GL_FALSE); 500 pScreen->GetImage(&pixmap->drawable, 0 /*pixmap->drawable.x*/, 501 0 /*pixmap->drawable.y*/, pixmap->drawable.width, 502 pixmap->drawable.height, ZPixmap, ~0, data); 503 __glXleaveServer(GL_FALSE); 504 505 if (pixmap->drawable.depth == 24) 506 glxFillAlphaChannel(data, 507 pitch, 508 pixmap->drawable.width, 509 pixmap->drawable.height); 510 511 CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH, 512 pitch / bpp) ); 513 CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) ); 514 CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) ); 515 } 516 517 CALL_TexImage2D( GET_DISPATCH(), 518 (glxPixmap->target, 519 0, 520 bpp == 4 ? 4 : 3, 521 pixmap->drawable.width, 522 pixmap->drawable.height, 523 0, 524 format, 525 type, 526 data) ); 527 528 free(data); 529 } else if (!override) { 530 int i, numRects; 531 BoxPtr p; 532 533 numRects = RegionNumRects (pRegion); 534 p = RegionRects (pRegion); 535 536 CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) ); 537 CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) ); 538 539 for (i = 0; i < numRects; i++) 540 { 541 unsigned pitch = PixmapBytePad(p[i].x2 - p[i].x1, 542 pixmap->drawable.depth); 543 void *data = malloc(pitch * (p[i].y2 - p[i].y1)); 544 545 __glXenterServer(GL_FALSE); 546 pScreen->GetImage(&pixmap->drawable, /*pixmap->drawable.x +*/ p[i].x1, 547 /*pixmap->drawable.y*/ + p[i].y1, p[i].x2 - p[i].x1, 548 p[i].y2 - p[i].y1, ZPixmap, ~0, data); 549 __glXleaveServer(GL_FALSE); 550 551 if (pixmap->drawable.depth == 24) 552 glxFillAlphaChannel(data, 553 pitch, 554 p[i].x2 - p[i].x1, 555 p[i].y2 - p[i].y1); 556 557 CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH, 558 pitch / bpp) ); 559 560 CALL_TexSubImage2D( GET_DISPATCH(), 561 (glxPixmap->target, 562 0, 563 p[i].x1, p[i].y1, 564 p[i].x2 - p[i].x1, p[i].y2 - p[i].y1, 565 format, 566 type, 567 data) ); 568 569 free(data); 570 } 571 } 572 573 if (!override) 574 DamageEmpty(driDraw->pDamage); 575 576 return Success; 577} 578 579static int 580__glXDRIreleaseTexImage(__GLXcontext *baseContext, 581 int buffer, 582 __GLXdrawable *pixmap) 583{ 584 __GLXDRIscreen *screen = 585 (__GLXDRIscreen *) glxGetScreen(pixmap->pDraw->pScreen); 586 __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) pixmap; 587 588 __glXDRIdoReleaseTexImage(screen, drawable); 589 590 return Success; 591} 592 593static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { 594 __glXDRIbindTexImage, 595 __glXDRIreleaseTexImage 596}; 597 598static void 599__glXDRIscreenDestroy(__GLXscreen *baseScreen) 600{ 601 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 602 603 screen->core->destroyScreen(screen->driScreen); 604 605 dlclose(screen->driver); 606 607 __glXScreenDestroy(baseScreen); 608 609 free(screen); 610} 611 612static __GLXcontext * 613__glXDRIscreenCreateContext(__GLXscreen *baseScreen, 614 __GLXconfig *glxConfig, 615 __GLXcontext *baseShareContext) 616{ 617 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 618 __GLXDRIcontext *context, *shareContext; 619 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 620 VisualPtr visual; 621 int i; 622 GLboolean retval; 623 __DRIcontext *driShare; 624 drm_context_t hwContext; 625 ScreenPtr pScreen = baseScreen->pScreen; 626 627 shareContext = (__GLXDRIcontext *) baseShareContext; 628 if (shareContext) 629 driShare = shareContext->driContext; 630 else 631 driShare = NULL; 632 633 if (baseShareContext && baseShareContext->isDirect) 634 return NULL; 635 636 context = calloc(1, sizeof *context); 637 if (context == NULL) 638 return NULL; 639 640 context->base.destroy = __glXDRIcontextDestroy; 641 context->base.makeCurrent = __glXDRIcontextMakeCurrent; 642 context->base.loseCurrent = __glXDRIcontextLoseCurrent; 643 context->base.copy = __glXDRIcontextCopy; 644 context->base.forceCurrent = __glXDRIcontextForceCurrent; 645 646 context->base.textureFromPixmap = &__glXDRItextureFromPixmap; 647 /* Find the requested X visual */ 648 visual = pScreen->visuals; 649 for (i = 0; i < pScreen->numVisuals; i++, visual++) 650 if (visual->vid == glxConfig->visualID) 651 break; 652 if (i == pScreen->numVisuals) 653 return NULL; 654 655 context->hwContextID = FakeClientID(0); 656 657 __glXenterServer(GL_FALSE); 658 retval = DRICreateContext(baseScreen->pScreen, visual, 659 context->hwContextID, &hwContext); 660 __glXleaveServer(GL_FALSE); 661 662 if (!retval) 663 return NULL; 664 665 context->driContext = 666 screen->legacy->createNewContext(screen->driScreen, 667 config->driConfig, 668 0, /* render type */ 669 driShare, 670 hwContext, 671 context); 672 673 if (context->driContext == NULL) { 674 __glXenterServer(GL_FALSE); 675 retval = DRIDestroyContext(baseScreen->pScreen, context->hwContextID); 676 __glXleaveServer(GL_FALSE); 677 free(context); 678 return NULL; 679 } 680 681 return &context->base; 682} 683 684static __GLXdrawable * 685__glXDRIscreenCreateDrawable(ClientPtr client, 686 __GLXscreen *screen, 687 DrawablePtr pDraw, 688 XID drawId, 689 int type, 690 XID glxDrawId, 691 __GLXconfig *glxConfig) 692{ 693 __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; 694 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 695 __GLXDRIdrawable *private; 696 GLboolean retval; 697 drm_drawable_t hwDrawable; 698 699 private = calloc(1, sizeof *private); 700 if (private == NULL) 701 return NULL; 702 703 if (!__glXDrawableInit(&private->base, screen, 704 pDraw, type, glxDrawId, glxConfig)) { 705 free(private); 706 return NULL; 707 } 708 709 private->base.destroy = __glXDRIdrawableDestroy; 710 private->base.swapBuffers = __glXDRIdrawableSwapBuffers; 711 private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; 712 private->base.waitX = NULL; 713 private->base.waitGL = NULL; 714 715 __glXenterServer(GL_FALSE); 716 retval = DRICreateDrawable(screen->pScreen, serverClient, 717 pDraw, &hwDrawable); 718 __glXleaveServer(GL_FALSE); 719 720 if (!retval) { 721 free(private); 722 return NULL; 723 } 724 725 /* The last argument is 'attrs', which is used with pbuffers which 726 * we currently don't support. */ 727 728 private->driDrawable = 729 (driScreen->legacy->createNewDrawable)(driScreen->driScreen, 730 config->driConfig, 731 hwDrawable, 0, NULL, private); 732 733 if (private->driDrawable == NULL) { 734 __glXenterServer(GL_FALSE); 735 DRIDestroyDrawable(screen->pScreen, serverClient, pDraw); 736 __glXleaveServer(GL_FALSE); 737 free(private); 738 return NULL; 739 } 740 741 return &private->base; 742} 743 744static GLboolean 745getDrawableInfo(__DRIdrawable *driDrawable, 746 unsigned int *index, unsigned int *stamp, 747 int *x, int *y, int *width, int *height, 748 int *numClipRects, drm_clip_rect_t **ppClipRects, 749 int *backX, int *backY, 750 int *numBackClipRects, drm_clip_rect_t **ppBackClipRects, 751 void *data) 752{ 753 __GLXDRIdrawable *drawable = data; 754 ScreenPtr pScreen; 755 drm_clip_rect_t *pClipRects, *pBackClipRects; 756 GLboolean retval; 757 size_t size; 758 759 /* If the X window has been destroyed, give up here. */ 760 if (drawable->base.pDraw == NULL) 761 return GL_FALSE; 762 763 pScreen = drawable->base.pDraw->pScreen; 764 __glXenterServer(GL_FALSE); 765 retval = DRIGetDrawableInfo(pScreen, drawable->base.pDraw, index, stamp, 766 x, y, width, height, 767 numClipRects, &pClipRects, 768 backX, backY, 769 numBackClipRects, &pBackClipRects); 770 __glXleaveServer(GL_FALSE); 771 772 if (retval && *numClipRects > 0) { 773 size = sizeof (drm_clip_rect_t) * *numClipRects; 774 *ppClipRects = malloc(size); 775 776 /* Clip cliprects to screen dimensions (redirected windows) */ 777 if (*ppClipRects != NULL) { 778 int i, j; 779 780 for (i = 0, j = 0; i < *numClipRects; i++) { 781 (*ppClipRects)[j].x1 = max(pClipRects[i].x1, 0); 782 (*ppClipRects)[j].y1 = max(pClipRects[i].y1, 0); 783 (*ppClipRects)[j].x2 = min(pClipRects[i].x2, pScreen->width); 784 (*ppClipRects)[j].y2 = min(pClipRects[i].y2, pScreen->height); 785 786 if ((*ppClipRects)[j].x1 < (*ppClipRects)[j].x2 && 787 (*ppClipRects)[j].y1 < (*ppClipRects)[j].y2) { 788 j++; 789 } 790 } 791 792 if (*numClipRects != j) { 793 *numClipRects = j; 794 *ppClipRects = realloc(*ppClipRects, 795 sizeof (drm_clip_rect_t) * 796 *numClipRects); 797 } 798 } else 799 *numClipRects = 0; 800 } 801 else { 802 *ppClipRects = NULL; 803 *numClipRects = 0; 804 } 805 806 if (retval && *numBackClipRects > 0) { 807 size = sizeof (drm_clip_rect_t) * *numBackClipRects; 808 *ppBackClipRects = malloc(size); 809 if (*ppBackClipRects != NULL) 810 memcpy (*ppBackClipRects, pBackClipRects, size); 811 else 812 *numBackClipRects = 0; 813 } 814 else { 815 *ppBackClipRects = NULL; 816 *numBackClipRects = 0; 817 } 818 819 return retval; 820} 821 822static void __glXReportDamage(__DRIdrawable *driDraw, 823 int x, int y, 824 drm_clip_rect_t *rects, int num_rects, 825 GLboolean front_buffer, 826 void *data) 827{ 828 __GLXDRIdrawable *drawable = data; 829 DrawablePtr pDraw = drawable->base.pDraw; 830 RegionRec region; 831 832 __glXenterServer(GL_FALSE); 833 834 if (RegionInitBoxes(®ion, (BoxPtr) rects, num_rects)) { 835 RegionTranslate(®ion, pDraw->x, pDraw->y); 836 DamageDamageRegion(pDraw, ®ion); 837 RegionUninit(®ion); 838 } 839 else { 840 while (num_rects--) { 841 RegionInit (®ion, (BoxPtr) rects++, 1); 842 RegionTranslate(®ion, pDraw->x, pDraw->y); 843 DamageDamageRegion(pDraw, ®ion); 844 RegionUninit(®ion); 845 } 846 } 847 848 __glXleaveServer(GL_FALSE); 849} 850 851static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = { 852 { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION }, 853 getDrawableInfo 854}; 855 856static const __DRIdamageExtension damageExtension = { 857 { __DRI_DAMAGE, __DRI_DAMAGE_VERSION }, 858 __glXReportDamage, 859}; 860 861static const __DRIextension *loader_extensions[] = { 862 &systemTimeExtension.base, 863 &getDrawableInfoExtension.base, 864 &damageExtension.base, 865 NULL 866}; 867 868 869 870static const char dri_driver_path[] = DRI_DRIVER_PATH; 871 872static Bool 873glxDRIEnterVT (int index, int flags) 874{ 875 ScrnInfoPtr scrn = xf86Screens[index]; 876 Bool ret; 877 __GLXDRIscreen *screen = (__GLXDRIscreen *) 878 glxGetScreen(screenInfo.screens[index]); 879 880 LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n"); 881 882 scrn->EnterVT = screen->enterVT; 883 884 ret = scrn->EnterVT (index, flags); 885 886 screen->enterVT = scrn->EnterVT; 887 scrn->EnterVT = glxDRIEnterVT; 888 889 if (!ret) 890 return FALSE; 891 892 glxResumeClients(); 893 894 return TRUE; 895} 896 897static void 898glxDRILeaveVT (int index, int flags) 899{ 900 ScrnInfoPtr scrn = xf86Screens[index]; 901 __GLXDRIscreen *screen = (__GLXDRIscreen *) 902 glxGetScreen(screenInfo.screens[index]); 903 904 LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n"); 905 906 glxSuspendClients(); 907 908 scrn->LeaveVT = screen->leaveVT; 909 (*screen->leaveVT) (index, flags); 910 screen->leaveVT = scrn->LeaveVT; 911 scrn->LeaveVT = glxDRILeaveVT; 912} 913 914static void 915initializeExtensions(__GLXDRIscreen *screen) 916{ 917 const __DRIextension **extensions; 918 int i; 919 920 extensions = screen->core->getExtensions(screen->driScreen); 921 922 for (i = 0; extensions[i]; i++) { 923#ifdef __DRI_READ_DRAWABLE 924 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { 925 __glXEnableExtension(screen->glx_enable_bits, 926 "GLX_SGI_make_current_read"); 927 928 LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); 929 } 930#endif 931 932#ifdef __DRI_COPY_SUB_BUFFER 933 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { 934 screen->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i]; 935 __glXEnableExtension(screen->glx_enable_bits, 936 "GLX_MESA_copy_sub_buffer"); 937 938 LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); 939 } 940#endif 941 942#ifdef __DRI_SWAP_CONTROL 943 if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) { 944 screen->swapControl = (__DRIswapControlExtension *) extensions[i]; 945 __glXEnableExtension(screen->glx_enable_bits, 946 "GLX_SGI_swap_control"); 947 __glXEnableExtension(screen->glx_enable_bits, 948 "GLX_MESA_swap_control"); 949 950 LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); 951 } 952#endif 953 954#ifdef __DRI_TEX_OFFSET 955 if (strcmp(extensions[i]->name, __DRI_TEX_OFFSET) == 0) { 956 screen->texOffset = (__DRItexOffsetExtension *) extensions[i]; 957 LogMessage(X_INFO, "AIGLX: enabled GLX_texture_from_pixmap with driver support\n"); 958 } 959#endif 960 /* Ignore unknown extensions */ 961 } 962} 963 964static __GLXscreen * 965__glXDRIscreenProbe(ScreenPtr pScreen) 966{ 967 drm_handle_t hSAREA; 968 drmAddress pSAREA = NULL; 969 char *BusID; 970 __DRIversion ddx_version; 971 __DRIversion dri_version; 972 __DRIversion drm_version; 973 __DRIframebuffer framebuffer; 974 int fd = -1; 975 int status; 976 drm_magic_t magic; 977 drmVersionPtr version; 978 int newlyopened; 979 char *driverName; 980 drm_handle_t hFB; 981 int junk; 982 __GLXDRIscreen *screen; 983 char filename[128]; 984 Bool isCapable; 985 size_t buffer_size; 986 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 987 const __DRIconfig **driConfigs; 988 const __DRIextension **extensions; 989 int i; 990 991 memset(&framebuffer, 0, sizeof(framebuffer)); 992 993 if (!xf86LoaderCheckSymbol("DRIQueryDirectRenderingCapable") || 994 !DRIQueryDirectRenderingCapable(pScreen, &isCapable) || 995 !isCapable) { 996 LogMessage(X_INFO, 997 "AIGLX: Screen %d is not DRI capable\n", pScreen->myNum); 998 return NULL; 999 } 1000 1001 screen = calloc(1, sizeof *screen); 1002 if (screen == NULL) 1003 return NULL; 1004 1005 screen->base.destroy = __glXDRIscreenDestroy; 1006 screen->base.createContext = __glXDRIscreenCreateContext; 1007 screen->base.createDrawable = __glXDRIscreenCreateDrawable; 1008 screen->base.swapInterval = __glXDRIdrawableSwapInterval; 1009 screen->base.pScreen = pScreen; 1010 1011 __glXInitExtensionEnableBits(screen->glx_enable_bits); 1012 1013 /* DRI protocol version. */ 1014 dri_version.major = XF86DRI_MAJOR_VERSION; 1015 dri_version.minor = XF86DRI_MINOR_VERSION; 1016 dri_version.patch = XF86DRI_PATCH_VERSION; 1017 1018 if (!DRIOpenConnection(pScreen, &hSAREA, &BusID)) { 1019 LogMessage(X_ERROR, "AIGLX error: DRIOpenConnection failed\n"); 1020 goto handle_error; 1021 } 1022 1023 fd = drmOpenOnce(NULL, BusID, &newlyopened); 1024 1025 if (fd < 0) { 1026 LogMessage(X_ERROR, "AIGLX error: drmOpenOnce failed (%s)\n", 1027 strerror(-fd)); 1028 goto handle_error; 1029 } 1030 1031 if (drmGetMagic(fd, &magic)) { 1032 LogMessage(X_ERROR, "AIGLX error: drmGetMagic failed\n"); 1033 goto handle_error; 1034 } 1035 1036 version = drmGetVersion(fd); 1037 if (version) { 1038 drm_version.major = version->version_major; 1039 drm_version.minor = version->version_minor; 1040 drm_version.patch = version->version_patchlevel; 1041 drmFreeVersion(version); 1042 } 1043 else { 1044 drm_version.major = -1; 1045 drm_version.minor = -1; 1046 drm_version.patch = -1; 1047 } 1048 1049 if (newlyopened && !DRIAuthConnection(pScreen, magic)) { 1050 LogMessage(X_ERROR, "AIGLX error: DRIAuthConnection failed\n"); 1051 goto handle_error; 1052 } 1053 1054 /* Get device name (like "tdfx") and the ddx version numbers. 1055 * We'll check the version in each DRI driver's "createNewScreen" 1056 * function. */ 1057 if (!DRIGetClientDriverName(pScreen, 1058 &ddx_version.major, 1059 &ddx_version.minor, 1060 &ddx_version.patch, 1061 &driverName)) { 1062 LogMessage(X_ERROR, "AIGLX error: DRIGetClientDriverName failed\n"); 1063 goto handle_error; 1064 } 1065 1066 snprintf(filename, sizeof filename, "%s/%s_dri.so", 1067 dri_driver_path, driverName); 1068 1069 screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL); 1070 if (screen->driver == NULL) { 1071 LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n", 1072 filename, dlerror()); 1073 goto handle_error; 1074 } 1075 1076 extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS); 1077 if (extensions == NULL) { 1078 LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n", 1079 driverName, dlerror()); 1080 goto handle_error; 1081 } 1082 1083 for (i = 0; extensions[i]; i++) { 1084 if (strcmp(extensions[i]->name, __DRI_CORE) == 0 && 1085 extensions[i]->version >= __DRI_CORE_VERSION) { 1086 screen->core = (__DRIcoreExtension *) extensions[i]; 1087 } 1088 1089 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0 && 1090 extensions[i]->version >= __DRI_LEGACY_VERSION) { 1091 screen->legacy = (__DRIlegacyExtension *) extensions[i]; 1092 } 1093 } 1094 1095 if (screen->core == NULL || screen->legacy == NULL) { 1096 LogMessage(X_ERROR, 1097 "AIGLX error: %s does not export required DRI extension\n", 1098 driverName); 1099 goto handle_error; 1100 } 1101 1102 /* 1103 * Get device-specific info. pDevPriv will point to a struct 1104 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that 1105 * has information about the screen size, depth, pitch, ancilliary 1106 * buffers, DRM mmap handles, etc. 1107 */ 1108 if (!DRIGetDeviceInfo(pScreen, &hFB, &junk, 1109 &framebuffer.size, &framebuffer.stride, 1110 &framebuffer.dev_priv_size, &framebuffer.dev_priv)) { 1111 LogMessage(X_ERROR, "AIGLX error: XF86DRIGetDeviceInfo failed\n"); 1112 goto handle_error; 1113 } 1114 1115 framebuffer.width = pScreen->width; 1116 framebuffer.height = pScreen->height; 1117 1118 /* Map the framebuffer region. */ 1119 status = drmMap(fd, hFB, framebuffer.size, 1120 (drmAddressPtr)&framebuffer.base); 1121 if (status != 0) { 1122 LogMessage(X_ERROR, "AIGLX error: drmMap of framebuffer failed (%s)\n", 1123 strerror(-status)); 1124 goto handle_error; 1125 } 1126 1127 /* Map the SAREA region. Further mmap regions may be setup in 1128 * each DRI driver's "createNewScreen" function. 1129 */ 1130 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA); 1131 if (status != 0) { 1132 LogMessage(X_ERROR, "AIGLX error: drmMap of SAREA failed (%s)\n", 1133 strerror(-status)); 1134 goto handle_error; 1135 } 1136 1137 screen->driScreen = 1138 (*screen->legacy->createNewScreen)(pScreen->myNum, 1139 &ddx_version, 1140 &dri_version, 1141 &drm_version, 1142 &framebuffer, 1143 pSAREA, 1144 fd, 1145 loader_extensions, 1146 &driConfigs, 1147 screen); 1148 1149 if (screen->driScreen == NULL) { 1150 LogMessage(X_ERROR, 1151 "AIGLX error: Calling driver entry point failed\n"); 1152 goto handle_error; 1153 } 1154 1155 screen->base.fbconfigs = glxConvertConfigs(screen->core, 1156 driConfigs, GLX_WINDOW_BIT); 1157 1158 initializeExtensions(screen); 1159 1160 DRIGetTexOffsetFuncs(pScreen, &screen->texOffsetStart, 1161 &screen->texOffsetFinish); 1162 1163 __glXScreenInit(&screen->base, pScreen); 1164 1165 /* The first call simply determines the length of the extension string. 1166 * This allows us to allocate some memory to hold the extension string, 1167 * but it requires that we call __glXGetExtensionString a second time. 1168 */ 1169 buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); 1170 if (buffer_size > 0) { 1171 free(screen->base.GLXextensions); 1172 1173 screen->base.GLXextensions = xnfalloc(buffer_size); 1174 (void) __glXGetExtensionString(screen->glx_enable_bits, 1175 screen->base.GLXextensions); 1176 } 1177 1178 __glXsetEnterLeaveServerFuncs(__glXDRIenterServer, __glXDRIleaveServer); 1179 1180 screen->enterVT = pScrn->EnterVT; 1181 pScrn->EnterVT = glxDRIEnterVT; 1182 screen->leaveVT = pScrn->LeaveVT; 1183 pScrn->LeaveVT = glxDRILeaveVT; 1184 1185 LogMessage(X_INFO, 1186 "AIGLX: Loaded and initialized %s\n", filename); 1187 1188 return &screen->base; 1189 1190 handle_error: 1191 if (pSAREA != NULL) 1192 drmUnmap(pSAREA, SAREA_MAX); 1193 1194 if (framebuffer.base != NULL) 1195 drmUnmap((drmAddress)framebuffer.base, framebuffer.size); 1196 1197 if (fd >= 0) 1198 drmCloseOnce(fd); 1199 1200 DRICloseConnection(pScreen); 1201 1202 if (screen->driver) 1203 dlclose(screen->driver); 1204 1205 free(screen); 1206 1207 LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); 1208 1209 return NULL; 1210} 1211 1212_X_EXPORT __GLXprovider __glXDRIProvider = { 1213 __glXDRIscreenProbe, 1214 "DRI", 1215 NULL 1216}; 1217