1/* 2 * Copyright © 2007 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 <dlfcn.h> 33 34#include <drm.h> 35#include <GL/gl.h> 36#include <GL/internal/dri_interface.h> 37#include <GL/glxtokens.h> 38 39#include <windowstr.h> 40#include <os.h> 41 42#define _XF86DRI_SERVER_ 43#include <xf86drm.h> 44#include <xf86.h> 45#include <dri2.h> 46 47#include "glxserver.h" 48#include "glxutil.h" 49#include "glxdricommon.h" 50 51#include "glapitable.h" 52#include "glapi.h" 53#include "glthread.h" 54#include "dispatch.h" 55#include "extension_string.h" 56 57typedef struct __GLXDRIscreen __GLXDRIscreen; 58typedef struct __GLXDRIcontext __GLXDRIcontext; 59typedef struct __GLXDRIdrawable __GLXDRIdrawable; 60 61struct __GLXDRIscreen { 62 __GLXscreen base; 63 __DRIscreen *driScreen; 64 void *driver; 65 int fd; 66 67 xf86EnterVTProc *enterVT; 68 xf86LeaveVTProc *leaveVT; 69 70 const __DRIcoreExtension *core; 71 const __DRIdri2Extension *dri2; 72 const __DRI2flushExtension *flush; 73 const __DRIcopySubBufferExtension *copySubBuffer; 74 const __DRIswapControlExtension *swapControl; 75 const __DRItexBufferExtension *texBuffer; 76 77 unsigned char glx_enable_bits[__GLX_EXT_BYTES]; 78}; 79 80struct __GLXDRIcontext { 81 __GLXcontext base; 82 __DRIcontext *driContext; 83}; 84 85#define MAX_DRAWABLE_BUFFERS 5 86 87struct __GLXDRIdrawable { 88 __GLXdrawable base; 89 __DRIdrawable *driDrawable; 90 __GLXDRIscreen *screen; 91 92 /* Dimensions as last reported by DRI2GetBuffers. */ 93 int width; 94 int height; 95 __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS]; 96 int count; 97}; 98 99static void 100__glXDRIdrawableDestroy(__GLXdrawable *drawable) 101{ 102 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 103 const __DRIcoreExtension *core = private->screen->core; 104 105 (*core->destroyDrawable)(private->driDrawable); 106 107 __glXDrawableRelease(drawable); 108 109 free(private); 110} 111 112static void 113__glXDRIdrawableCopySubBuffer(__GLXdrawable *drawable, 114 int x, int y, int w, int h) 115{ 116 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 117 BoxRec box; 118 RegionRec region; 119 120 box.x1 = x; 121 box.y1 = private->height - y - h; 122 box.x2 = x + w; 123 box.y2 = private->height - y; 124 RegionInit(®ion, &box, 0); 125 126 DRI2CopyRegion(drawable->pDraw, ®ion, 127 DRI2BufferFrontLeft, DRI2BufferBackLeft); 128} 129 130static void 131__glXDRIdrawableWaitX(__GLXdrawable *drawable) 132{ 133 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 134 BoxRec box; 135 RegionRec region; 136 137 box.x1 = 0; 138 box.y1 = 0; 139 box.x2 = private->width; 140 box.y2 = private->height; 141 RegionInit(®ion, &box, 0); 142 143 DRI2CopyRegion(drawable->pDraw, ®ion, 144 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 145} 146 147static void 148__glXDRIdrawableWaitGL(__GLXdrawable *drawable) 149{ 150 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 151 BoxRec box; 152 RegionRec region; 153 154 box.x1 = 0; 155 box.y1 = 0; 156 box.x2 = private->width; 157 box.y2 = private->height; 158 RegionInit(®ion, &box, 0); 159 160 DRI2CopyRegion(drawable->pDraw, ®ion, 161 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 162} 163 164static void 165__glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust, 166 CARD64 msc, CARD64 sbc) 167{ 168 __GLXdrawable *drawable = data; 169 xGLXBufferSwapComplete wire; 170 171 if (!(drawable->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) 172 return; 173 174 wire.type = __glXEventBase + GLX_BufferSwapComplete; 175 switch (type) { 176 case DRI2_EXCHANGE_COMPLETE: 177 wire.event_type = GLX_EXCHANGE_COMPLETE_INTEL; 178 break; 179 case DRI2_BLIT_COMPLETE: 180 wire.event_type = GLX_BLIT_COMPLETE_INTEL; 181 break; 182 case DRI2_FLIP_COMPLETE: 183 wire.event_type = GLX_FLIP_COMPLETE_INTEL; 184 break; 185 default: 186 /* unknown swap completion type */ 187 wire.event_type = 0; 188 break; 189 } 190 wire.drawable = drawable->drawId; 191 wire.ust_hi = ust >> 32; 192 wire.ust_lo = ust & 0xffffffff; 193 wire.msc_hi = msc >> 32; 194 wire.msc_lo = msc & 0xffffffff; 195 wire.sbc_hi = sbc >> 32; 196 wire.sbc_lo = sbc & 0xffffffff; 197 198 WriteEventsToClient(client, 1, (xEvent *) &wire); 199} 200 201/* 202 * Copy or flip back to front, honoring the swap interval if possible. 203 * 204 * If the kernel supports it, we request an event for the frame when the 205 * swap should happen, then perform the copy when we receive it. 206 */ 207static GLboolean 208__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable) 209{ 210 __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable; 211 __GLXDRIscreen *screen = priv->screen; 212 CARD64 unused; 213 214#if __DRI2_FLUSH_VERSION >= 3 215 if (screen->flush) { 216 (*screen->flush->flush)(priv->driDrawable); 217 (*screen->flush->invalidate)(priv->driDrawable); 218 } 219#else 220 if (screen->flush) 221 (*screen->flush->flushInvalidate)(priv->driDrawable); 222#endif 223 224 if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused, 225 __glXdriSwapEvent, drawable->pDraw) != Success) 226 return FALSE; 227 228 return TRUE; 229} 230 231static int 232__glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval) 233{ 234 if (interval <= 0) /* || interval > BIGNUM? */ 235 return GLX_BAD_VALUE; 236 237 DRI2SwapInterval(drawable->pDraw, interval); 238 239 return 0; 240} 241 242static void 243__glXDRIcontextDestroy(__GLXcontext *baseContext) 244{ 245 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 246 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 247 248 (*screen->core->destroyContext)(context->driContext); 249 __glXContextDestroy(&context->base); 250 free(context); 251} 252 253static int 254__glXDRIcontextMakeCurrent(__GLXcontext *baseContext) 255{ 256 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 257 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 258 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 259 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 260 261 return (*screen->core->bindContext)(context->driContext, 262 draw->driDrawable, 263 read->driDrawable); 264} 265 266static int 267__glXDRIcontextLoseCurrent(__GLXcontext *baseContext) 268{ 269 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 270 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 271 272 return (*screen->core->unbindContext)(context->driContext); 273} 274 275static int 276__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, 277 unsigned long mask) 278{ 279 __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; 280 __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; 281 __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; 282 283 return (*screen->core->copyContext)(dst->driContext, 284 src->driContext, mask); 285} 286 287static int 288__glXDRIcontextForceCurrent(__GLXcontext *baseContext) 289{ 290 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 291 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 292 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 293 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 294 295 return (*screen->core->bindContext)(context->driContext, 296 draw->driDrawable, 297 read->driDrawable); 298} 299 300static Bool 301__glXDRIcontextWait(__GLXcontext *baseContext, 302 __GLXclientState *cl, int *error) 303{ 304 if (DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw)) { 305 *error = cl->client->noClientException; 306 return TRUE; 307 } 308 309 return FALSE; 310} 311 312#ifdef __DRI_TEX_BUFFER 313 314static int 315__glXDRIbindTexImage(__GLXcontext *baseContext, 316 int buffer, 317 __GLXdrawable *glxPixmap) 318{ 319 __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; 320 const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; 321 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 322 323 if (texBuffer == NULL) 324 return Success; 325 326#if __DRI_TEX_BUFFER_VERSION >= 2 327 if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) { 328 (*texBuffer->setTexBuffer2)(context->driContext, 329 glxPixmap->target, 330 glxPixmap->format, 331 drawable->driDrawable); 332 } else 333#endif 334 { 335 texBuffer->setTexBuffer(context->driContext, 336 glxPixmap->target, 337 drawable->driDrawable); 338 } 339 340 return Success; 341} 342 343static int 344__glXDRIreleaseTexImage(__GLXcontext *baseContext, 345 int buffer, 346 __GLXdrawable *pixmap) 347{ 348 /* FIXME: Just unbind the texture? */ 349 return Success; 350} 351 352#else 353 354static int 355__glXDRIbindTexImage(__GLXcontext *baseContext, 356 int buffer, 357 __GLXdrawable *glxPixmap) 358{ 359 return Success; 360} 361 362static int 363__glXDRIreleaseTexImage(__GLXcontext *baseContext, 364 int buffer, 365 __GLXdrawable *pixmap) 366{ 367 return Success; 368} 369 370#endif 371 372static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { 373 __glXDRIbindTexImage, 374 __glXDRIreleaseTexImage 375}; 376 377static void 378__glXDRIscreenDestroy(__GLXscreen *baseScreen) 379{ 380 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 381 382 (*screen->core->destroyScreen)(screen->driScreen); 383 384 dlclose(screen->driver); 385 386 __glXScreenDestroy(baseScreen); 387 388 free(screen); 389} 390 391static __GLXcontext * 392__glXDRIscreenCreateContext(__GLXscreen *baseScreen, 393 __GLXconfig *glxConfig, 394 __GLXcontext *baseShareContext) 395{ 396 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 397 __GLXDRIcontext *context, *shareContext; 398 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 399 __DRIcontext *driShare; 400 401 shareContext = (__GLXDRIcontext *) baseShareContext; 402 if (shareContext) 403 driShare = shareContext->driContext; 404 else 405 driShare = NULL; 406 407 context = calloc(1, sizeof *context); 408 if (context == NULL) 409 return NULL; 410 411 context->base.destroy = __glXDRIcontextDestroy; 412 context->base.makeCurrent = __glXDRIcontextMakeCurrent; 413 context->base.loseCurrent = __glXDRIcontextLoseCurrent; 414 context->base.copy = __glXDRIcontextCopy; 415 context->base.forceCurrent = __glXDRIcontextForceCurrent; 416 context->base.textureFromPixmap = &__glXDRItextureFromPixmap; 417 context->base.wait = __glXDRIcontextWait; 418 419 context->driContext = 420 (*screen->dri2->createNewContext)(screen->driScreen, 421 config->driConfig, 422 driShare, context); 423 if (context->driContext == NULL) { 424 free(context); 425 return NULL; 426 } 427 428 return &context->base; 429} 430 431static void 432__glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv) 433{ 434#if __DRI2_FLUSH_VERSION >= 3 435 __GLXDRIdrawable *private = priv; 436 __GLXDRIscreen *screen = private->screen; 437 438 if (screen->flush) 439 (*screen->flush->invalidate)(private->driDrawable); 440#endif 441} 442 443static __GLXdrawable * 444__glXDRIscreenCreateDrawable(ClientPtr client, 445 __GLXscreen *screen, 446 DrawablePtr pDraw, 447 XID drawId, 448 int type, 449 XID glxDrawId, 450 __GLXconfig *glxConfig) 451{ 452 __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; 453 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 454 __GLXDRIdrawable *private; 455 456 private = calloc(1, sizeof *private); 457 if (private == NULL) 458 return NULL; 459 460 private->screen = driScreen; 461 if (!__glXDrawableInit(&private->base, screen, 462 pDraw, type, glxDrawId, glxConfig)) { 463 free(private); 464 return NULL; 465 } 466 467 private->base.destroy = __glXDRIdrawableDestroy; 468 private->base.swapBuffers = __glXDRIdrawableSwapBuffers; 469 private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; 470 private->base.waitGL = __glXDRIdrawableWaitGL; 471 private->base.waitX = __glXDRIdrawableWaitX; 472 473 if (DRI2CreateDrawable(client, pDraw, drawId, 474 __glXDRIinvalidateBuffers, private)) { 475 free(private); 476 return NULL; 477 } 478 479 private->driDrawable = 480 (*driScreen->dri2->createNewDrawable)(driScreen->driScreen, 481 config->driConfig, private); 482 483 return &private->base; 484} 485 486static __DRIbuffer * 487dri2GetBuffers(__DRIdrawable *driDrawable, 488 int *width, int *height, 489 unsigned int *attachments, int count, 490 int *out_count, void *loaderPrivate) 491{ 492 __GLXDRIdrawable *private = loaderPrivate; 493 DRI2BufferPtr *buffers; 494 int i; 495 int j; 496 497 buffers = DRI2GetBuffers(private->base.pDraw, 498 width, height, attachments, count, out_count); 499 if (*out_count > MAX_DRAWABLE_BUFFERS) { 500 *out_count = 0; 501 return NULL; 502 } 503 504 private->width = *width; 505 private->height = *height; 506 507 /* This assumes the DRI2 buffer attachment tokens matches the 508 * __DRIbuffer tokens. */ 509 j = 0; 510 for (i = 0; i < *out_count; i++) { 511 /* Do not send the real front buffer of a window to the client. 512 */ 513 if ((private->base.pDraw->type == DRAWABLE_WINDOW) 514 && (buffers[i]->attachment == DRI2BufferFrontLeft)) { 515 continue; 516 } 517 518 private->buffers[j].attachment = buffers[i]->attachment; 519 private->buffers[j].name = buffers[i]->name; 520 private->buffers[j].pitch = buffers[i]->pitch; 521 private->buffers[j].cpp = buffers[i]->cpp; 522 private->buffers[j].flags = buffers[i]->flags; 523 j++; 524 } 525 526 *out_count = j; 527 return private->buffers; 528} 529 530static __DRIbuffer * 531dri2GetBuffersWithFormat(__DRIdrawable *driDrawable, 532 int *width, int *height, 533 unsigned int *attachments, int count, 534 int *out_count, void *loaderPrivate) 535{ 536 __GLXDRIdrawable *private = loaderPrivate; 537 DRI2BufferPtr *buffers; 538 int i; 539 int j = 0; 540 541 buffers = DRI2GetBuffersWithFormat(private->base.pDraw, 542 width, height, attachments, count, 543 out_count); 544 if (*out_count > MAX_DRAWABLE_BUFFERS) { 545 *out_count = 0; 546 return NULL; 547 } 548 549 private->width = *width; 550 private->height = *height; 551 552 /* This assumes the DRI2 buffer attachment tokens matches the 553 * __DRIbuffer tokens. */ 554 for (i = 0; i < *out_count; i++) { 555 /* Do not send the real front buffer of a window to the client. 556 */ 557 if ((private->base.pDraw->type == DRAWABLE_WINDOW) 558 && (buffers[i]->attachment == DRI2BufferFrontLeft)) { 559 continue; 560 } 561 562 private->buffers[j].attachment = buffers[i]->attachment; 563 private->buffers[j].name = buffers[i]->name; 564 private->buffers[j].pitch = buffers[i]->pitch; 565 private->buffers[j].cpp = buffers[i]->cpp; 566 private->buffers[j].flags = buffers[i]->flags; 567 j++; 568 } 569 570 *out_count = j; 571 return private->buffers; 572} 573 574static void 575dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 576{ 577 (void) driDrawable; 578 __glXDRIdrawableWaitGL((__GLXdrawable *) loaderPrivate); 579} 580 581static const __DRIdri2LoaderExtension loaderExtension = { 582 { __DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION }, 583 dri2GetBuffers, 584 dri2FlushFrontBuffer, 585 dri2GetBuffersWithFormat, 586}; 587 588#ifdef __DRI_USE_INVALIDATE 589static const __DRIuseInvalidateExtension dri2UseInvalidate = { 590 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 591}; 592#endif 593 594static const __DRIextension *loader_extensions[] = { 595 &systemTimeExtension.base, 596 &loaderExtension.base, 597#ifdef __DRI_USE_INVALIDATE 598 &dri2UseInvalidate.base, 599#endif 600 NULL 601}; 602 603static const char dri_driver_path[] = DRI_DRIVER_PATH; 604 605static Bool 606glxDRIEnterVT (int index, int flags) 607{ 608 ScrnInfoPtr scrn = xf86Screens[index]; 609 Bool ret; 610 __GLXDRIscreen *screen = (__GLXDRIscreen *) 611 glxGetScreen(screenInfo.screens[index]); 612 613 LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n"); 614 615 scrn->EnterVT = screen->enterVT; 616 617 ret = scrn->EnterVT (index, flags); 618 619 screen->enterVT = scrn->EnterVT; 620 scrn->EnterVT = glxDRIEnterVT; 621 622 if (!ret) 623 return FALSE; 624 625 glxResumeClients(); 626 627 return TRUE; 628} 629 630static void 631glxDRILeaveVT (int index, int flags) 632{ 633 ScrnInfoPtr scrn = xf86Screens[index]; 634 __GLXDRIscreen *screen = (__GLXDRIscreen *) 635 glxGetScreen(screenInfo.screens[index]); 636 637 LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n"); 638 639 glxSuspendClients(); 640 641 scrn->LeaveVT = screen->leaveVT; 642 (*screen->leaveVT) (index, flags); 643 screen->leaveVT = scrn->LeaveVT; 644 scrn->LeaveVT = glxDRILeaveVT; 645} 646 647static void 648initializeExtensions(__GLXDRIscreen *screen) 649{ 650 ScreenPtr pScreen = screen->base.pScreen; 651 const __DRIextension **extensions; 652 int i; 653 654 extensions = screen->core->getExtensions(screen->driScreen); 655 656 __glXEnableExtension(screen->glx_enable_bits, 657 "GLX_MESA_copy_sub_buffer"); 658 LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); 659 660 __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event"); 661 LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n"); 662 663 if (DRI2HasSwapControl(pScreen)) { 664 __glXEnableExtension(screen->glx_enable_bits, 665 "GLX_SGI_swap_control"); 666 __glXEnableExtension(screen->glx_enable_bits, 667 "GLX_MESA_swap_control"); 668 LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); 669 } 670 671 for (i = 0; extensions[i]; i++) { 672#ifdef __DRI_READ_DRAWABLE 673 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { 674 __glXEnableExtension(screen->glx_enable_bits, 675 "GLX_SGI_make_current_read"); 676 677 LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); 678 } 679#endif 680 681#ifdef __DRI_TEX_BUFFER 682 if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { 683 screen->texBuffer = 684 (const __DRItexBufferExtension *) extensions[i]; 685 /* GLX_EXT_texture_from_pixmap is always enabled. */ 686 LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); 687 } 688#endif 689 690#ifdef __DRI2_FLUSH 691 if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 && 692 extensions[i]->version >= 3) { 693 screen->flush = (__DRI2flushExtension *) extensions[i]; 694 } 695#endif 696 697 /* Ignore unknown extensions */ 698 } 699} 700 701static __GLXscreen * 702__glXDRIscreenProbe(ScreenPtr pScreen) 703{ 704 const char *driverName, *deviceName; 705 __GLXDRIscreen *screen; 706 char filename[128]; 707 size_t buffer_size; 708 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 709 const __DRIextension **extensions; 710 const __DRIconfig **driConfigs; 711 int i; 712 713 screen = calloc(1, sizeof *screen); 714 if (screen == NULL) 715 return NULL; 716 717 if (!xf86LoaderCheckSymbol("DRI2Connect") || 718 !DRI2Connect(pScreen, DRI2DriverDRI, 719 &screen->fd, &driverName, &deviceName)) { 720 LogMessage(X_INFO, 721 "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum); 722 return NULL; 723 } 724 725 screen->base.destroy = __glXDRIscreenDestroy; 726 screen->base.createContext = __glXDRIscreenCreateContext; 727 screen->base.createDrawable = __glXDRIscreenCreateDrawable; 728 screen->base.swapInterval = __glXDRIdrawableSwapInterval; 729 screen->base.pScreen = pScreen; 730 731 __glXInitExtensionEnableBits(screen->glx_enable_bits); 732 733 snprintf(filename, sizeof filename, 734 "%s/%s_dri.so", dri_driver_path, driverName); 735 736 screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL); 737 if (screen->driver == NULL) { 738 LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n", 739 filename, dlerror()); 740 goto handle_error; 741 } 742 743 extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS); 744 if (extensions == NULL) { 745 LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n", 746 driverName, dlerror()); 747 goto handle_error; 748 } 749 750 for (i = 0; extensions[i]; i++) { 751 if (strcmp(extensions[i]->name, __DRI_CORE) == 0 && 752 extensions[i]->version >= 1) { 753 screen->core = (const __DRIcoreExtension *) extensions[i]; 754 } 755 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0 && 756 extensions[i]->version >= 1) { 757 screen->dri2 = (const __DRIdri2Extension *) extensions[i]; 758 } 759 } 760 761 if (screen->core == NULL || screen->dri2 == NULL) { 762 LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n", 763 driverName); 764 goto handle_error; 765 } 766 767 screen->driScreen = 768 (*screen->dri2->createNewScreen)(pScreen->myNum, 769 screen->fd, 770 loader_extensions, 771 &driConfigs, 772 screen); 773 774 if (screen->driScreen == NULL) { 775 LogMessage(X_ERROR, 776 "AIGLX error: Calling driver entry point failed\n"); 777 goto handle_error; 778 } 779 780 initializeExtensions(screen); 781 782 screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs, 783 GLX_WINDOW_BIT | 784 GLX_PIXMAP_BIT | 785 GLX_PBUFFER_BIT); 786 787 __glXScreenInit(&screen->base, pScreen); 788 789 /* The first call simply determines the length of the extension string. 790 * This allows us to allocate some memory to hold the extension string, 791 * but it requires that we call __glXGetExtensionString a second time. 792 */ 793 buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); 794 if (buffer_size > 0) { 795 free(screen->base.GLXextensions); 796 797 screen->base.GLXextensions = xnfalloc(buffer_size); 798 (void) __glXGetExtensionString(screen->glx_enable_bits, 799 screen->base.GLXextensions); 800 } 801 802 /* We're going to assume (perhaps incorrectly?) that all DRI2-enabled 803 * drivers support the required extensions for GLX 1.4. The extensions 804 * we're assuming are: 805 * 806 * - GLX_SGI_make_current_read (1.3) 807 * - GLX_SGIX_fbconfig (1.3) 808 * - GLX_SGIX_pbuffer (1.3) 809 * - GLX_ARB_multisample (1.4) 810 */ 811 screen->base.GLXmajor = 1; 812 screen->base.GLXminor = 4; 813 814 screen->enterVT = pScrn->EnterVT; 815 pScrn->EnterVT = glxDRIEnterVT; 816 screen->leaveVT = pScrn->LeaveVT; 817 pScrn->LeaveVT = glxDRILeaveVT; 818 819 LogMessage(X_INFO, 820 "AIGLX: Loaded and initialized %s\n", filename); 821 822 return &screen->base; 823 824 handle_error: 825 if (screen->driver) 826 dlclose(screen->driver); 827 828 free(screen); 829 830 LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); 831 832 return NULL; 833} 834 835_X_EXPORT __GLXprovider __glXDRI2Provider = { 836 __glXDRIscreenProbe, 837 "DRI2", 838 NULL 839}; 840