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