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