dri_glx.c revision 089fc37c6fa158824279e08e3b378ced94d6f803
1/************************************************************************** 2 3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 4All Rights Reserved. 5 6Permission is hereby granted, free of charge, to any person obtaining a 7copy of this software and associated documentation files (the 8"Software"), to deal in the Software without restriction, including 9without limitation the rights to use, copy, modify, merge, publish, 10distribute, sub license, and/or sell copies of the Software, and to 11permit persons to whom the Software is furnished to do so, subject to 12the following conditions: 13 14The above copyright notice and this permission notice (including the 15next paragraph) shall be included in all copies or substantial portions 16of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 22ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 26**************************************************************************/ 27 28/* 29 * Authors: 30 * Kevin E. Martin <kevin@precisioninsight.com> 31 * Brian Paul <brian@precisioninsight.com> 32 * 33 */ 34 35#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 36 37#include <X11/Xlib.h> 38#include <X11/extensions/Xfixes.h> 39#include <X11/extensions/Xdamage.h> 40#include "glxclient.h" 41#include "xf86dri.h" 42#include "dri2.h" 43#include "sarea.h" 44#include <dlfcn.h> 45#include <sys/types.h> 46#include <sys/mman.h> 47#include "xf86drm.h" 48#include "dri_common.h" 49 50struct dri_display 51{ 52 __GLXDRIdisplay base; 53 54 /* 55 ** XFree86-DRI version information 56 */ 57 int driMajor; 58 int driMinor; 59 int driPatch; 60}; 61 62struct dri_screen 63{ 64 __GLXscreenConfigs base; 65 66 __GLXDRIscreen driScreen; 67 const __DRIlegacyExtension *legacy; 68 const __DRIcoreExtension *core; 69 const __DRIswapControlExtension *swapControl; 70 const __DRImediaStreamCounterExtension *msc; 71 72 void *driver; 73 int fd; 74}; 75 76struct dri_context 77{ 78 __GLXDRIcontext base; 79 __DRIcontext *driContext; 80 XID hwContextID; 81 __GLXscreenConfigs *psc; 82}; 83 84/* 85 * Given a display pointer and screen number, determine the name of 86 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc). 87 * Return True for success, False for failure. 88 */ 89static Bool 90driGetDriverName(Display * dpy, int scrNum, char **driverName) 91{ 92 int directCapable; 93 Bool b; 94 int event, error; 95 int driverMajor, driverMinor, driverPatch; 96 97 *driverName = NULL; 98 99 if (XF86DRIQueryExtension(dpy, &event, &error)) { /* DRI1 */ 100 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) { 101 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n"); 102 return False; 103 } 104 if (!directCapable) { 105 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n"); 106 return False; 107 } 108 109 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor, 110 &driverPatch, driverName); 111 if (!b) { 112 ErrorMessageF("Cannot determine driver name for screen %d\n", 113 scrNum); 114 return False; 115 } 116 117 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n", 118 driverMajor, driverMinor, driverPatch, *driverName, 119 scrNum); 120 121 return True; 122 } 123 else if (DRI2QueryExtension(dpy, &event, &error)) { /* DRI2 */ 124 char *dev; 125 Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev); 126 127 if (ret) 128 Xfree(dev); 129 130 return ret; 131 } 132 133 return False; 134} 135 136/* 137 * Exported function for querying the DRI driver for a given screen. 138 * 139 * The returned char pointer points to a static array that will be 140 * overwritten by subsequent calls. 141 */ 142PUBLIC const char * 143glXGetScreenDriver(Display * dpy, int scrNum) 144{ 145 static char ret[32]; 146 char *driverName; 147 if (driGetDriverName(dpy, scrNum, &driverName)) { 148 int len; 149 if (!driverName) 150 return NULL; 151 len = strlen(driverName); 152 if (len >= 31) 153 return NULL; 154 memcpy(ret, driverName, len + 1); 155 Xfree(driverName); 156 return ret; 157 } 158 return NULL; 159} 160 161/* 162 * Exported function for obtaining a driver's option list (UTF-8 encoded XML). 163 * 164 * The returned char pointer points directly into the driver. Therefore 165 * it should be treated as a constant. 166 * 167 * If the driver was not found or does not support configuration NULL is 168 * returned. 169 * 170 * Note: The driver remains opened after this function returns. 171 */ 172PUBLIC const char * 173glXGetDriverConfig(const char *driverName) 174{ 175 void *handle = driOpenDriver(driverName); 176 if (handle) 177 return dlsym(handle, "__driConfigOptions"); 178 else 179 return NULL; 180} 181 182#ifdef XDAMAGE_1_1_INTERFACE 183 184static GLboolean 185has_damage_post(Display * dpy) 186{ 187 static GLboolean inited = GL_FALSE; 188 static GLboolean has_damage; 189 190 if (!inited) { 191 int major, minor; 192 193 if (XDamageQueryVersion(dpy, &major, &minor) && 194 major == 1 && minor >= 1) { 195 has_damage = GL_TRUE; 196 } 197 else { 198 has_damage = GL_FALSE; 199 } 200 inited = GL_TRUE; 201 } 202 203 return has_damage; 204} 205 206static void 207__glXReportDamage(__DRIdrawable * driDraw, 208 int x, int y, 209 drm_clip_rect_t * rects, int num_rects, 210 GLboolean front_buffer, void *loaderPrivate) 211{ 212 XRectangle *xrects; 213 XserverRegion region; 214 int i; 215 int x_off, y_off; 216 __GLXDRIdrawable *glxDraw = loaderPrivate; 217 __GLXscreenConfigs *psc = glxDraw->psc; 218 Display *dpy = psc->dpy; 219 Drawable drawable; 220 221 if (!has_damage_post(dpy)) 222 return; 223 224 if (front_buffer) { 225 x_off = x; 226 y_off = y; 227 drawable = RootWindow(dpy, psc->scr); 228 } 229 else { 230 x_off = 0; 231 y_off = 0; 232 drawable = glxDraw->xDrawable; 233 } 234 235 xrects = malloc(sizeof(XRectangle) * num_rects); 236 if (xrects == NULL) 237 return; 238 239 for (i = 0; i < num_rects; i++) { 240 xrects[i].x = rects[i].x1 + x_off; 241 xrects[i].y = rects[i].y1 + y_off; 242 xrects[i].width = rects[i].x2 - rects[i].x1; 243 xrects[i].height = rects[i].y2 - rects[i].y1; 244 } 245 region = XFixesCreateRegion(dpy, xrects, num_rects); 246 free(xrects); 247 XDamageAdd(dpy, drawable, region); 248 XFixesDestroyRegion(dpy, region); 249} 250 251static const __DRIdamageExtension damageExtension = { 252 {__DRI_DAMAGE, __DRI_DAMAGE_VERSION}, 253 __glXReportDamage, 254}; 255 256#endif 257 258static GLboolean 259__glXDRIGetDrawableInfo(__DRIdrawable * drawable, 260 unsigned int *index, unsigned int *stamp, 261 int *X, int *Y, int *W, int *H, 262 int *numClipRects, drm_clip_rect_t ** pClipRects, 263 int *backX, int *backY, 264 int *numBackClipRects, 265 drm_clip_rect_t ** pBackClipRects, 266 void *loaderPrivate) 267{ 268 __GLXDRIdrawable *glxDraw = loaderPrivate; 269 __GLXscreenConfigs *psc = glxDraw->psc; 270 Display *dpy = psc->dpy; 271 272 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable, 273 index, stamp, X, Y, W, H, 274 numClipRects, pClipRects, 275 backX, backY, 276 numBackClipRects, pBackClipRects); 277} 278 279static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = { 280 {__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION}, 281 __glXDRIGetDrawableInfo 282}; 283 284static const __DRIextension *loader_extensions[] = { 285 &systemTimeExtension.base, 286 &getDrawableInfoExtension.base, 287#ifdef XDAMAGE_1_1_INTERFACE 288 &damageExtension.base, 289#endif 290 NULL 291}; 292 293/** 294 * Perform the required libGL-side initialization and call the client-side 295 * driver's \c __driCreateNewScreen function. 296 * 297 * \param dpy Display pointer. 298 * \param scrn Screen number on the display. 299 * \param psc DRI screen information. 300 * \param driDpy DRI display information. 301 * \param createNewScreen Pointer to the client-side driver's 302 * \c __driCreateNewScreen function. 303 * \returns A pointer to the \c __DRIscreen structure returned by 304 * the client-side driver on success, or \c NULL on failure. 305 */ 306static void * 307CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc, 308 struct dri_display * driDpy) 309{ 310 void *psp = NULL; 311 drm_handle_t hSAREA; 312 drmAddress pSAREA = MAP_FAILED; 313 char *BusID; 314 __DRIversion ddx_version; 315 __DRIversion dri_version; 316 __DRIversion drm_version; 317 __DRIframebuffer framebuffer; 318 int fd = -1; 319 int status; 320 321 drm_magic_t magic; 322 drmVersionPtr version; 323 int newlyopened; 324 char *driverName; 325 drm_handle_t hFB; 326 int junk; 327 const __DRIconfig **driver_configs; 328 __GLcontextModes *visual; 329 330 /* DRI protocol version. */ 331 dri_version.major = driDpy->driMajor; 332 dri_version.minor = driDpy->driMinor; 333 dri_version.patch = driDpy->driPatch; 334 335 framebuffer.base = MAP_FAILED; 336 framebuffer.dev_priv = NULL; 337 framebuffer.size = 0; 338 339 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) { 340 ErrorMessageF("XF86DRIOpenConnection failed\n"); 341 goto handle_error; 342 } 343 344 fd = drmOpenOnce(NULL, BusID, &newlyopened); 345 346 Xfree(BusID); /* No longer needed */ 347 348 if (fd < 0) { 349 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd)); 350 goto handle_error; 351 } 352 353 if (drmGetMagic(fd, &magic)) { 354 ErrorMessageF("drmGetMagic failed\n"); 355 goto handle_error; 356 } 357 358 version = drmGetVersion(fd); 359 if (version) { 360 drm_version.major = version->version_major; 361 drm_version.minor = version->version_minor; 362 drm_version.patch = version->version_patchlevel; 363 drmFreeVersion(version); 364 } 365 else { 366 drm_version.major = -1; 367 drm_version.minor = -1; 368 drm_version.patch = -1; 369 } 370 371 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) { 372 ErrorMessageF("XF86DRIAuthConnection failed\n"); 373 goto handle_error; 374 } 375 376 /* Get device name (like "tdfx") and the ddx version numbers. 377 * We'll check the version in each DRI driver's "createNewScreen" 378 * function. */ 379 if (!XF86DRIGetClientDriverName(dpy, scrn, 380 &ddx_version.major, 381 &ddx_version.minor, 382 &ddx_version.patch, &driverName)) { 383 ErrorMessageF("XF86DRIGetClientDriverName failed\n"); 384 goto handle_error; 385 } 386 387 Xfree(driverName); /* No longer needed. */ 388 389 /* 390 * Get device-specific info. pDevPriv will point to a struct 391 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that 392 * has information about the screen size, depth, pitch, ancilliary 393 * buffers, DRM mmap handles, etc. 394 */ 395 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk, 396 &framebuffer.size, &framebuffer.stride, 397 &framebuffer.dev_priv_size, 398 &framebuffer.dev_priv)) { 399 ErrorMessageF("XF86DRIGetDeviceInfo failed"); 400 goto handle_error; 401 } 402 403 framebuffer.width = DisplayWidth(dpy, scrn); 404 framebuffer.height = DisplayHeight(dpy, scrn); 405 406 /* Map the framebuffer region. */ 407 status = drmMap(fd, hFB, framebuffer.size, 408 (drmAddressPtr) & framebuffer.base); 409 if (status != 0) { 410 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status)); 411 goto handle_error; 412 } 413 414 /* Map the SAREA region. Further mmap regions may be setup in 415 * each DRI driver's "createNewScreen" function. 416 */ 417 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA); 418 if (status != 0) { 419 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status)); 420 goto handle_error; 421 } 422 423 psp = (*psc->legacy->createNewScreen) (scrn, 424 &ddx_version, 425 &dri_version, 426 &drm_version, 427 &framebuffer, 428 pSAREA, 429 fd, 430 loader_extensions, 431 &driver_configs, psc); 432 433 if (psp == NULL) { 434 ErrorMessageF("Calling driver entry point failed"); 435 goto handle_error; 436 } 437 438 psc->base.configs = 439 driConvertConfigs(psc->core, psc->base.configs, driver_configs); 440 psc->base.visuals = 441 driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 442 443 psc->base.driver_configs = driver_configs; 444 445 /* Visuals with depth != screen depth are subject to automatic compositing 446 * in the X server, so DRI1 can't render to them properly. Mark them as 447 * non-conformant to prevent apps from picking them up accidentally. 448 */ 449 for (visual = psc->base.visuals; visual; visual = visual->next) { 450 XVisualInfo template; 451 XVisualInfo *visuals; 452 int num_visuals; 453 long mask; 454 455 template.visualid = visual->visualID; 456 mask = VisualIDMask; 457 visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals); 458 459 if (visuals) { 460 if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn)) 461 visual->visualRating = GLX_NON_CONFORMANT_CONFIG; 462 463 XFree(visuals); 464 } 465 } 466 467 return psp; 468 469 handle_error: 470 if (pSAREA != MAP_FAILED) 471 drmUnmap(pSAREA, SAREA_MAX); 472 473 if (framebuffer.base != MAP_FAILED) 474 drmUnmap((drmAddress) framebuffer.base, framebuffer.size); 475 476 if (framebuffer.dev_priv != NULL) 477 Xfree(framebuffer.dev_priv); 478 479 if (fd >= 0) 480 drmCloseOnce(fd); 481 482 XF86DRICloseConnection(dpy, scrn); 483 484 ErrorMessageF("reverting to software direct rendering\n"); 485 486 return NULL; 487} 488 489static void 490driDestroyContext(__GLXDRIcontext * context, 491 __GLXscreenConfigs *base, Display * dpy) 492{ 493 struct dri_context *pcp = (struct dri_context *) context; 494 struct dri_screen *psc = (struct dri_screen *) base; 495 496 (*psc->core->destroyContext) (pcp->driContext); 497 498 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID); 499 Xfree(pcp); 500} 501 502static Bool 503driBindContext(__GLXDRIcontext *context, 504 __GLXDRIdrawable *draw, __GLXDRIdrawable *read) 505{ 506 struct dri_context *pcp = (struct dri_context *) context; 507 struct dri_screen *psc = (struct dri_screen *) pcp->psc; 508 509 return (*psc->core->bindContext) (pcp->driContext, 510 draw->driDrawable, read->driDrawable); 511} 512 513static void 514driUnbindContext(__GLXDRIcontext * context) 515{ 516 struct dri_context *pcp = (struct dri_context *) context; 517 struct dri_screen *psc = (struct dri_screen *) pcp->psc; 518 519 (*psc->core->unbindContext) (pcp->driContext); 520} 521 522static __GLXDRIcontext * 523driCreateContext(__GLXscreenConfigs *base, 524 const __GLcontextModes * mode, 525 GLXContext gc, GLXContext shareList, int renderType) 526{ 527 struct dri_context *pcp, *pcp_shared; 528 struct dri_screen *psc = (struct dri_screen *) base; 529 drm_context_t hwContext; 530 __DRIcontext *shared = NULL; 531 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode; 532 533 if (!psc->base.driScreen) 534 return NULL; 535 536 if (shareList) { 537 pcp_shared = (struct dri_context *) shareList->driContext; 538 shared = pcp_shared->driContext; 539 } 540 541 pcp = Xmalloc(sizeof *pcp); 542 if (pcp == NULL) 543 return NULL; 544 545 pcp->psc = &psc->base; 546 if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr, 547 mode->visualID, 548 &pcp->hwContextID, &hwContext)) { 549 Xfree(pcp); 550 return NULL; 551 } 552 553 pcp->driContext = 554 (*psc->legacy->createNewContext) (psc->base.__driScreen, 555 config->driConfig, 556 renderType, shared, hwContext, pcp); 557 if (pcp->driContext == NULL) { 558 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID); 559 Xfree(pcp); 560 return NULL; 561 } 562 563 pcp->base.destroyContext = driDestroyContext; 564 pcp->base.bindContext = driBindContext; 565 pcp->base.unbindContext = driUnbindContext; 566 567 return &pcp->base; 568} 569 570static void 571driDestroyDrawable(__GLXDRIdrawable * pdraw) 572{ 573 struct dri_screen *psc = (struct dri_screen *) pdraw->psc; 574 575 (*psc->core->destroyDrawable) (pdraw->driDrawable); 576 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable); 577 Xfree(pdraw); 578} 579 580static __GLXDRIdrawable * 581driCreateDrawable(__GLXscreenConfigs *base, 582 XID xDrawable, 583 GLXDrawable drawable, const __GLcontextModes * modes) 584{ 585 __GLXDRIdrawable *pdraw; 586 drm_drawable_t hwDrawable; 587 void *empty_attribute_list = NULL; 588 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; 589 struct dri_screen *psc = (struct dri_screen *) base; 590 591 /* Old dri can't handle GLX 1.3+ drawable constructors. */ 592 if (xDrawable != drawable) 593 return NULL; 594 595 pdraw = Xmalloc(sizeof(*pdraw)); 596 if (!pdraw) 597 return NULL; 598 599 pdraw->drawable = drawable; 600 pdraw->psc = &psc->base; 601 602 if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr, 603 drawable, &hwDrawable)) { 604 Xfree(pdraw); 605 return NULL; 606 } 607 608 /* Create a new drawable */ 609 pdraw->driDrawable = 610 (*psc->legacy->createNewDrawable) (psc->base.__driScreen, 611 config->driConfig, 612 hwDrawable, 613 GLX_WINDOW_BIT, 614 empty_attribute_list, pdraw); 615 616 if (!pdraw->driDrawable) { 617 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable); 618 Xfree(pdraw); 619 return NULL; 620 } 621 622 pdraw->destroyDrawable = driDestroyDrawable; 623 624 return pdraw; 625} 626 627static int64_t 628driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2, 629 int64_t unused3) 630{ 631 struct dri_screen *psc = (struct dri_screen *) pdraw->psc; 632 633 (*psc->core->swapBuffers) (pdraw->driDrawable); 634 return 0; 635} 636 637static void 638driCopySubBuffer(__GLXDRIdrawable * pdraw, 639 int x, int y, int width, int height) 640{ 641 (*pdraw->psc->driCopySubBuffer->copySubBuffer) (pdraw->driDrawable, 642 x, y, width, height); 643} 644 645static void 646driDestroyScreen(__GLXscreenConfigs *base) 647{ 648 struct dri_screen *psc = (struct dri_screen *) base; 649 650 /* Free the direct rendering per screen data */ 651 if (psc->base.__driScreen) 652 (*psc->core->destroyScreen) (psc->base.__driScreen); 653 psc->base.__driScreen = NULL; 654 if (psc->driver) 655 dlclose(psc->driver); 656} 657 658static const struct glx_context_vtable dri_context_vtable = { 659 NULL, 660 NULL, 661}; 662 663#ifdef __DRI_SWAP_BUFFER_COUNTER 664 665static int 666driDrawableGetMSC(__GLXscreenConfigs *base, __GLXDRIdrawable *pdraw, 667 int64_t *ust, int64_t *msc, int64_t *sbc) 668{ 669 struct dri_screen *psc = (struct dri_screen *) base; 670 671 if (pdraw && psc->sbc && psc->msc) 672 return ( (*psc->msc->getMSC)(psc->driScreen, msc) == 0 && 673 (*psc->sbc->getSBC)(pdraw->driDrawable, sbc) == 0 && 674 __glXGetUST(ust) == 0 ); 675} 676 677static int 678driWaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 679 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 680{ 681 struct dri_screen *psc = (struct dri_screen *) pdraw->psc; 682 683 if (pdraw != NULL && psc->msc != NULL) { 684 ret = (*psc->msc->waitForMSC) (pdraw->driDrawable, target_msc, 685 divisor, remainder, msc, sbc); 686 687 /* __glXGetUST returns zero on success and non-zero on failure. 688 * This function returns True on success and False on failure. 689 */ 690 return ret == 0 && __glXGetUST(ust) == 0; 691 } 692} 693 694static int 695driWaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 696 int64_t *msc, int64_t *sbc) 697{ 698 if (pdraw != NULL && psc->sbc != NULL) { 699 ret = 700 (*psc->sbc->waitForSBC) (pdraw->driDrawable, target_sbc, msc, sbc); 701 702 /* __glXGetUST returns zero on success and non-zero on failure. 703 * This function returns True on success and False on failure. 704 */ 705 return ((ret == 0) && (__glXGetUST(ust) == 0)); 706 } 707 708 return DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable, target_sbc, ust, msc, 709 sbc); 710} 711 712#endif 713 714static int 715driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 716{ 717 GLXContext gc = __glXGetCurrentContext(); 718 struct dri_screen *psc; 719 720 if (gc->driContext) { 721 psc = (struct dri_screen *) pdraw->psc; 722 723 if (psc->swapControl != NULL && pdraw != NULL) { 724 psc->swapControl->setSwapInterval(pdraw->driDrawable, interval); 725 return 0; 726 } 727 } 728 729 return GLX_BAD_CONTEXT; 730} 731 732static int 733driGetSwapInterval(__GLXDRIdrawable *pdraw) 734{ 735 GLXContext gc = __glXGetCurrentContext(); 736 struct dri_screen *psc; 737 738 if (gc != NULL && gc->driContext) { 739 psc = (struct dri_screen *) pdraw->psc; 740 741 if (psc->swapControl != NULL && pdraw != NULL) { 742 return psc->swapControl->getSwapInterval(pdraw->driDrawable); 743 } 744 } 745 746 return 0; 747} 748 749/* Bind DRI1 specific extensions */ 750static void 751driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions) 752{ 753 int i; 754 755 for (i = 0; extensions[i]; i++) { 756 /* No DRI2 support for swap_control at the moment, since SwapBuffers 757 * is done by the X server */ 758 if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) { 759 psc->swapControl = (__DRIswapControlExtension *) extensions[i]; 760 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 761 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 762 } 763 764 if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) { 765 psc->msc = (__DRImediaStreamCounterExtension *) extensions[i]; 766 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 767 } 768 769 /* Ignore unknown extensions */ 770 } 771} 772 773static __GLXscreenConfigs * 774driCreateScreen(int screen, __GLXdisplayPrivate *priv) 775{ 776 struct dri_display *pdp; 777 __GLXDRIscreen *psp; 778 const __DRIextension **extensions; 779 struct dri_screen *psc; 780 char *driverName; 781 int i; 782 783 psc = Xcalloc(1, sizeof *psc); 784 if (psc == NULL) 785 return NULL; 786 787 memset(psc, 0, sizeof *psc); 788 if (!glx_screen_init(&psc->base, screen, priv)) 789 return NULL; 790 791 if (!driGetDriverName(priv->dpy, screen, &driverName)) { 792 Xfree(psc); 793 return NULL; 794 } 795 796 psc->driver = driOpenDriver(driverName); 797 Xfree(driverName); 798 if (psc->driver == NULL) { 799 Xfree(psc); 800 return NULL; 801 } 802 803 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 804 if (extensions == NULL) { 805 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 806 Xfree(psc); 807 return NULL; 808 } 809 810 for (i = 0; extensions[i]; i++) { 811 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 812 psc->core = (__DRIcoreExtension *) extensions[i]; 813 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0) 814 psc->legacy = (__DRIlegacyExtension *) extensions[i]; 815 } 816 817 if (psc->core == NULL || psc->legacy == NULL) { 818 Xfree(psc); 819 return NULL; 820 } 821 822 pdp = (struct dri_display *) priv->driDisplay; 823 psc->base.__driScreen = 824 CallCreateNewScreen(psc->base.dpy, screen, psc, pdp); 825 if (psc->base.__driScreen == NULL) { 826 dlclose(psc->driver); 827 Xfree(psc); 828 return NULL; 829 } 830 831 extensions = psc->core->getExtensions(psc->base.__driScreen); 832 driBindExtensions(psc, extensions); 833 driBindCommonExtensions(&psc->base, extensions); 834 835 psp = &psc->driScreen; 836 psc->base.driScreen = psp; 837 if (psc->base.driCopySubBuffer) 838 psp->copySubBuffer = driCopySubBuffer; 839 840 psp->destroyScreen = driDestroyScreen; 841 psp->createContext = driCreateContext; 842 psp->createDrawable = driCreateDrawable; 843 psp->swapBuffers = driSwapBuffers; 844 psp->waitX = NULL; 845 psp->waitGL = NULL; 846 847#ifdef __DRI_SWAP_BUFFER_COUNTER 848 psp->getDrawableMSC = driDrawableGetMSC; 849 psp->waitForMSC = driWaitForMSC; 850 psp->waitForSBC = driWaitForSBC; 851#endif 852 853 psp->setSwapInterval = driSetSwapInterval; 854 psp->getSwapInterval = driGetSwapInterval; 855 856 psc->base.direct_context_vtable = &dri_context_vtable; 857 858 return &psc->base; 859} 860 861/* Called from __glXFreeDisplayPrivate. 862 */ 863static void 864driDestroyDisplay(__GLXDRIdisplay * dpy) 865{ 866 Xfree(dpy); 867} 868 869/* 870 * Allocate, initialize and return a __DRIdisplayPrivate object. 871 * This is called from __glXInitialize() when we are given a new 872 * display pointer. 873 */ 874_X_HIDDEN __GLXDRIdisplay * 875driCreateDisplay(Display * dpy) 876{ 877 struct dri_display *pdpyp; 878 int eventBase, errorBase; 879 int major, minor, patch; 880 881 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) { 882 return NULL; 883 } 884 885 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) { 886 return NULL; 887 } 888 889 pdpyp = Xmalloc(sizeof *pdpyp); 890 if (!pdpyp) { 891 return NULL; 892 } 893 894 pdpyp->driMajor = major; 895 pdpyp->driMinor = minor; 896 pdpyp->driPatch = patch; 897 898 pdpyp->base.destroyDisplay = driDestroyDisplay; 899 pdpyp->base.createScreen = driCreateScreen; 900 901 return &pdpyp->base; 902} 903 904#endif /* GLX_DIRECT_RENDERING */ 905