dri_glx.c revision 0e8e8ba29a7cbe2fe45939cb972f437ccd21bcd5
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. "r128", "tdfx", 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; 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 "tdfx") 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 psc->base.configs = 450 driConvertConfigs(psc->core, psc->base.configs, driver_configs); 451 psc->base.visuals = 452 driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 453 454 psc->driver_configs = driver_configs; 455 456 /* Visuals with depth != screen depth are subject to automatic compositing 457 * in the X server, so DRI1 can't render to them properly. Mark them as 458 * non-conformant to prevent apps from picking them up accidentally. 459 */ 460 for (visual = psc->base.visuals; visual; visual = visual->next) { 461 XVisualInfo template; 462 XVisualInfo *visuals; 463 int num_visuals; 464 long mask; 465 466 template.visualid = visual->visualID; 467 mask = VisualIDMask; 468 visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals); 469 470 if (visuals) { 471 if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn)) 472 visual->visualRating = GLX_NON_CONFORMANT_CONFIG; 473 474 XFree(visuals); 475 } 476 } 477 478 return psp; 479 480 handle_error: 481 if (pSAREA != MAP_FAILED) 482 drmUnmap(pSAREA, SAREA_MAX); 483 484 if (framebuffer.base != MAP_FAILED) 485 drmUnmap((drmAddress) framebuffer.base, framebuffer.size); 486 487 if (framebuffer.dev_priv != NULL) 488 Xfree(framebuffer.dev_priv); 489 490 if (fd >= 0) 491 drmCloseOnce(fd); 492 493 XF86DRICloseConnection(dpy, scrn); 494 495 ErrorMessageF("reverting to software direct rendering\n"); 496 497 return NULL; 498} 499 500static void 501dri_destroy_context(struct glx_context * context) 502{ 503 struct dri_context *pcp = (struct dri_context *) context; 504 struct dri_screen *psc = (struct dri_screen *) context->psc; 505 506 if (context->xid) 507 glx_send_destroy_context(psc->base.dpy, context->xid); 508 509 if (context->extensions) 510 XFree((char *) context->extensions); 511 512 (*psc->core->destroyContext) (pcp->driContext); 513 514 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID); 515 Xfree(pcp); 516} 517 518static int 519dri_bind_context(struct glx_context *context, struct glx_context *old, 520 GLXDrawable draw, GLXDrawable read) 521{ 522 struct dri_context *pcp = (struct dri_context *) context; 523 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc; 524 struct dri_drawable *pdraw, *pread; 525 526 pdraw = (struct dri_drawable *) driFetchDrawable(context, draw); 527 pread = (struct dri_drawable *) driFetchDrawable(context, read); 528 529 if (pdraw == NULL || pread == NULL) 530 return GLXBadDrawable; 531 532 if ((*psc->core->bindContext) (pcp->driContext, 533 pdraw->driDrawable, pread->driDrawable)) 534 return Success; 535 536 return GLXBadContext; 537} 538 539static void 540dri_unbind_context(struct glx_context *context, struct glx_context *new) 541{ 542 struct dri_context *pcp = (struct dri_context *) context; 543 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc; 544 545 (*psc->core->unbindContext) (pcp->driContext); 546 547 driReleaseDrawables(&pcp->base); 548} 549 550static const struct glx_context_vtable dri_context_vtable = { 551 dri_destroy_context, 552 dri_bind_context, 553 dri_unbind_context, 554 NULL, 555 NULL, 556 DRI_glXUseXFont, 557 NULL, 558 NULL, 559}; 560 561static struct glx_context * 562dri_create_context(struct glx_screen *base, 563 struct glx_config *config_base, 564 struct glx_context *shareList, int renderType) 565{ 566 struct dri_context *pcp, *pcp_shared; 567 struct dri_screen *psc = (struct dri_screen *) base; 568 drm_context_t hwContext; 569 __DRIcontext *shared = NULL; 570 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 571 572 if (!psc->base.driScreen) 573 return NULL; 574 575 if (shareList) { 576 pcp_shared = (struct dri_context *) shareList; 577 shared = pcp_shared->driContext; 578 } 579 580 pcp = Xmalloc(sizeof *pcp); 581 if (pcp == NULL) 582 return NULL; 583 584 memset(pcp, 0, sizeof *pcp); 585 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 586 Xfree(pcp); 587 return NULL; 588 } 589 590 if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr, 591 config->base.visualID, 592 &pcp->hwContextID, &hwContext)) { 593 Xfree(pcp); 594 return NULL; 595 } 596 597 pcp->driContext = 598 (*psc->legacy->createNewContext) (psc->driScreen, 599 config->driConfig, 600 renderType, shared, hwContext, pcp); 601 if (pcp->driContext == NULL) { 602 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID); 603 Xfree(pcp); 604 return NULL; 605 } 606 607 pcp->base.vtable = &dri_context_vtable; 608 609 return &pcp->base; 610} 611 612static void 613driDestroyDrawable(__GLXDRIdrawable * pdraw) 614{ 615 struct dri_screen *psc = (struct dri_screen *) pdraw->psc; 616 struct dri_drawable *pdp = (struct dri_drawable *) pdraw; 617 618 (*psc->core->destroyDrawable) (pdp->driDrawable); 619 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable); 620 Xfree(pdraw); 621} 622 623static __GLXDRIdrawable * 624driCreateDrawable(struct glx_screen *base, 625 XID xDrawable, 626 GLXDrawable drawable, struct glx_config *config_base) 627{ 628 drm_drawable_t hwDrawable; 629 void *empty_attribute_list = NULL; 630 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 631 struct dri_screen *psc = (struct dri_screen *) base; 632 struct dri_drawable *pdp; 633 634 /* Old dri can't handle GLX 1.3+ drawable constructors. */ 635 if (xDrawable != drawable) 636 return NULL; 637 638 pdp = Xmalloc(sizeof *pdp); 639 if (!pdp) 640 return NULL; 641 642 memset(pdp, 0, sizeof *pdp); 643 pdp->base.drawable = drawable; 644 pdp->base.psc = &psc->base; 645 646 if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr, 647 drawable, &hwDrawable)) { 648 Xfree(pdp); 649 return NULL; 650 } 651 652 /* Create a new drawable */ 653 pdp->driDrawable = 654 (*psc->legacy->createNewDrawable) (psc->driScreen, 655 config->driConfig, 656 hwDrawable, 657 GLX_WINDOW_BIT, 658 empty_attribute_list, pdp); 659 660 if (!pdp->driDrawable) { 661 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable); 662 Xfree(pdp); 663 return NULL; 664 } 665 666 pdp->base.destroyDrawable = driDestroyDrawable; 667 668 return &pdp->base; 669} 670 671static int64_t 672driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2, 673 int64_t unused3) 674{ 675 struct dri_screen *psc = (struct dri_screen *) pdraw->psc; 676 struct dri_drawable *pdp = (struct dri_drawable *) pdraw; 677 678 (*psc->core->swapBuffers) (pdp->driDrawable); 679 return 0; 680} 681 682static void 683driCopySubBuffer(__GLXDRIdrawable * pdraw, 684 int x, int y, int width, int height) 685{ 686 struct dri_drawable *pdp = (struct dri_drawable *) pdraw; 687 struct dri_screen *psc = (struct dri_screen *) pdp->base.psc; 688 689 (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable, 690 x, y, width, height); 691} 692 693static void 694driDestroyScreen(struct glx_screen *base) 695{ 696 struct dri_screen *psc = (struct dri_screen *) base; 697 698 /* Free the direct rendering per screen data */ 699 if (psc->driScreen) 700 (*psc->core->destroyScreen) (psc->driScreen); 701 driDestroyConfigs(psc->driver_configs); 702 psc->driScreen = NULL; 703 if (psc->driver) 704 dlclose(psc->driver); 705} 706 707#ifdef __DRI_SWAP_BUFFER_COUNTER 708 709static int 710driDrawableGetMSC(struct glx_screen *base, __GLXDRIdrawable *pdraw, 711 int64_t *ust, int64_t *msc, int64_t *sbc) 712{ 713 struct dri_screen *psc = (struct dri_screen *) base; 714 struct dri_drawable *pdp = (struct dri_drawable *) pdraw; 715 716 if (pdp && psc->sbc && psc->msc) 717 return ( (*psc->msc->getMSC)(psc->driScreen, msc) == 0 && 718 (*psc->sbc->getSBC)(pdp->driDrawable, sbc) == 0 && 719 __glXGetUST(ust) == 0 ); 720} 721 722static int 723driWaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 724 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 725{ 726 struct dri_screen *psc = (struct dri_screen *) pdraw->psc; 727 struct dri_drawable *pdp = (struct dri_drawable *) pdraw; 728 729 if (pdp != NULL && psc->msc != NULL) { 730 ret = (*psc->msc->waitForMSC) (pdp->driDrawable, target_msc, 731 divisor, remainder, msc, sbc); 732 733 /* __glXGetUST returns zero on success and non-zero on failure. 734 * This function returns True on success and False on failure. 735 */ 736 return ret == 0 && __glXGetUST(ust) == 0; 737 } 738} 739 740static int 741driWaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 742 int64_t *msc, int64_t *sbc) 743{ 744 struct dri_drawable *pdp = (struct dri_drawable *) pdraw; 745 746 if (pdp != NULL && psc->sbc != NULL) { 747 ret = 748 (*psc->sbc->waitForSBC) (pdp->driDrawable, target_sbc, msc, sbc); 749 750 /* __glXGetUST returns zero on success and non-zero on failure. 751 * This function returns True on success and False on failure. 752 */ 753 return ((ret == 0) && (__glXGetUST(ust) == 0)); 754 } 755 756 return DRI2WaitSBC(pdp->base.psc->dpy, 757 pdp->base.xDrawable, target_sbc, ust, msc, sbc); 758} 759 760#endif 761 762static int 763driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 764{ 765 struct dri_drawable *pdp = (struct dri_drawable *) pdraw; 766 struct dri_screen *psc = (struct dri_screen *) pdraw->psc; 767 768 if (psc->swapControl != NULL && pdraw != NULL) { 769 psc->swapControl->setSwapInterval(pdp->driDrawable, interval); 770 return 0; 771 } 772 773 return GLX_BAD_CONTEXT; 774} 775 776static int 777driGetSwapInterval(__GLXDRIdrawable *pdraw) 778{ 779 struct dri_drawable *pdp = (struct dri_drawable *) pdraw; 780 struct dri_screen *psc = (struct dri_screen *) pdraw->psc; 781 782 if (psc->swapControl != NULL && pdraw != NULL) 783 return psc->swapControl->getSwapInterval(pdp->driDrawable); 784 785 return 0; 786} 787 788/* Bind DRI1 specific extensions */ 789static void 790driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions) 791{ 792 int i; 793 794 for (i = 0; extensions[i]; i++) { 795 /* No DRI2 support for swap_control at the moment, since SwapBuffers 796 * is done by the X server */ 797 if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) { 798 psc->swapControl = (__DRIswapControlExtension *) extensions[i]; 799 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 800 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 801 } 802 803 if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) { 804 psc->msc = (__DRImediaStreamCounterExtension *) extensions[i]; 805 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 806 } 807 808 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { 809 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i]; 810 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 811 } 812 813 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { 814 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 815 } 816 /* Ignore unknown extensions */ 817 } 818} 819 820static const struct glx_screen_vtable dri_screen_vtable = { 821 dri_create_context 822}; 823 824static struct glx_screen * 825driCreateScreen(int screen, struct glx_display *priv) 826{ 827 struct dri_display *pdp; 828 __GLXDRIscreen *psp; 829 const __DRIextension **extensions; 830 struct dri_screen *psc; 831 char *driverName; 832 int i; 833 834 psc = Xcalloc(1, sizeof *psc); 835 if (psc == NULL) 836 return NULL; 837 838 memset(psc, 0, sizeof *psc); 839 if (!glx_screen_init(&psc->base, screen, priv)) { 840 Xfree(psc); 841 return NULL; 842 } 843 844 if (!driGetDriverName(priv->dpy, screen, &driverName)) { 845 goto cleanup; 846 } 847 848 psc->driver = driOpenDriver(driverName); 849 Xfree(driverName); 850 if (psc->driver == NULL) 851 goto cleanup; 852 853 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 854 if (extensions == NULL) { 855 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 856 goto cleanup; 857 } 858 859 for (i = 0; extensions[i]; i++) { 860 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 861 psc->core = (__DRIcoreExtension *) extensions[i]; 862 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0) 863 psc->legacy = (__DRIlegacyExtension *) extensions[i]; 864 } 865 866 if (psc->core == NULL || psc->legacy == NULL) 867 goto cleanup; 868 869 pdp = (struct dri_display *) priv->driDisplay; 870 psc->driScreen = 871 CallCreateNewScreen(psc->base.dpy, screen, psc, pdp); 872 if (psc->driScreen == NULL) 873 goto cleanup; 874 875 extensions = psc->core->getExtensions(psc->driScreen); 876 driBindExtensions(psc, extensions); 877 878 psc->base.vtable = &dri_screen_vtable; 879 psp = &psc->vtable; 880 psc->base.driScreen = psp; 881 if (psc->driCopySubBuffer) 882 psp->copySubBuffer = driCopySubBuffer; 883 884 psp->destroyScreen = driDestroyScreen; 885 psp->createDrawable = driCreateDrawable; 886 psp->swapBuffers = driSwapBuffers; 887 888#ifdef __DRI_SWAP_BUFFER_COUNTER 889 psp->getDrawableMSC = driDrawableGetMSC; 890 psp->waitForMSC = driWaitForMSC; 891 psp->waitForSBC = driWaitForSBC; 892#endif 893 894 psp->setSwapInterval = driSetSwapInterval; 895 psp->getSwapInterval = driGetSwapInterval; 896 897 return &psc->base; 898 899cleanup: 900 if (psc->driver) 901 dlclose(psc->driver); 902 glx_screen_cleanup(&psc->base); 903 Xfree(psc); 904 905 return NULL; 906} 907 908/* Called from __glXFreeDisplayPrivate. 909 */ 910static void 911driDestroyDisplay(__GLXDRIdisplay * dpy) 912{ 913 Xfree(dpy); 914} 915 916/* 917 * Allocate, initialize and return a __DRIdisplayPrivate object. 918 * This is called from __glXInitialize() when we are given a new 919 * display pointer. 920 */ 921_X_HIDDEN __GLXDRIdisplay * 922driCreateDisplay(Display * dpy) 923{ 924 struct dri_display *pdpyp; 925 int eventBase, errorBase; 926 int major, minor, patch; 927 928 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) { 929 return NULL; 930 } 931 932 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) { 933 return NULL; 934 } 935 936 pdpyp = Xmalloc(sizeof *pdpyp); 937 if (!pdpyp) { 938 return NULL; 939 } 940 941 pdpyp->driMajor = major; 942 pdpyp->driMinor = minor; 943 pdpyp->driPatch = patch; 944 945 pdpyp->base.destroyDisplay = driDestroyDisplay; 946 pdpyp->base.createScreen = driCreateScreen; 947 948 return &pdpyp->base; 949} 950 951#endif /* GLX_DIRECT_RENDERING */ 952