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