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