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 "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 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 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 */ 98static Bool 99driGetDriverName(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 * 152glXGetScreenDriver(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 */ 174struct driver_config_entry { 175 struct driver_config_entry *next; 176 char *driverName; 177 char *config; 178}; 179 180static pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER; 181static 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 */ 186static Bool e_next_ever_null = False; 187 188static void __attribute__((__destructor__)) 189clear_driver_config_cache() 190{ 191 192 if (!e_next_ever_null) 193 return; 194 195 while (driver_config_cache) { 196 struct driver_config_entry *e = driver_config_cache; 197 driver_config_cache = e->next; 198 199 free(e->driverName); 200 free(e->config); 201 free(e); 202 } 203} 204 205static char * 206get_driver_config(const char *driverName) 207{ 208 void *handle; 209 char *config = NULL; 210 const __DRIextension **extensions = driOpenDriver(driverName, &handle); 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 * 250glXGetDriverConfig(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 e_next_ever_null = True; 280 281out: 282 pthread_mutex_unlock(&driver_config_mutex); 283 284 return e ? e->config : NULL; 285} 286 287static GLboolean 288has_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 309static 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 354static const __DRIdamageExtension damageExtension = { 355 .base = {__DRI_DAMAGE, 1 }, 356 357 .reportDamage = __glXReportDamage, 358}; 359 360static 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 381static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = { 382 .base = {__DRI_GET_DRAWABLE_INFO, 1 }, 383 384 .getDrawableInfo = __glXDRIGetDrawableInfo 385}; 386 387static 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 */ 409static void * 410CallCreateNewScreen(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 604static void 605dri_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 620static int 621dri_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 643static void 644dri_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 652static 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 664static struct glx_context * 665dri_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 727static void 728driDestroyDrawable(__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 738static __GLXDRIdrawable * 739driCreateDrawable(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 785static int64_t 786driSwapBuffers(__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 800static void 801driCopySubBuffer(__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 815static void 816driDestroyScreen(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 829static int 830driSetSwapInterval(__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 845static int 846driGetSwapInterval(__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 */ 860static void 861driBindExtensions(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 891static 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 898static struct glx_screen * 899driCreateScreen(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 extensions = driOpenDriver(driverName, &psc->driver); 922 if (extensions == NULL) { 923 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 924 goto cleanup; 925 } 926 927 for (i = 0; extensions[i]; i++) { 928 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 929 psc->core = (__DRIcoreExtension *) extensions[i]; 930 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0) 931 psc->legacy = (__DRIlegacyExtension *) extensions[i]; 932 } 933 934 if (psc->core == NULL || psc->legacy == NULL) 935 goto cleanup; 936 937 pdp = (struct dri_display *) priv->driDisplay; 938 psc->driScreen = 939 CallCreateNewScreen(psc->base.dpy, screen, psc, pdp); 940 if (psc->driScreen == NULL) 941 goto cleanup; 942 943 extensions = psc->core->getExtensions(psc->driScreen); 944 driBindExtensions(psc, extensions); 945 946 psc->base.vtable = &dri_screen_vtable; 947 psp = &psc->vtable; 948 psc->base.driScreen = psp; 949 if (psc->driCopySubBuffer) 950 psp->copySubBuffer = driCopySubBuffer; 951 952 psp->destroyScreen = driDestroyScreen; 953 psp->createDrawable = driCreateDrawable; 954 psp->swapBuffers = driSwapBuffers; 955 956 psp->setSwapInterval = driSetSwapInterval; 957 psp->getSwapInterval = driGetSwapInterval; 958 959 free(driverName); 960 961 return &psc->base; 962 963cleanup: 964 CriticalErrorMessageF("failed to load driver: %s\n", driverName); 965 966 free(driverName); 967 968 if (psc->driver) 969 dlclose(psc->driver); 970 glx_screen_cleanup(&psc->base); 971 free(psc); 972 973 return NULL; 974} 975 976/* Called from __glXFreeDisplayPrivate. 977 */ 978static void 979driDestroyDisplay(__GLXDRIdisplay * dpy) 980{ 981 free(dpy); 982} 983 984/* 985 * Allocate, initialize and return a __DRIdisplayPrivate object. 986 * This is called from __glXInitialize() when we are given a new 987 * display pointer. 988 */ 989_X_HIDDEN __GLXDRIdisplay * 990driCreateDisplay(Display * dpy) 991{ 992 struct dri_display *pdpyp; 993 int eventBase, errorBase; 994 int major, minor, patch; 995 996 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) { 997 return NULL; 998 } 999 1000 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) { 1001 return NULL; 1002 } 1003 1004 pdpyp = malloc(sizeof *pdpyp); 1005 if (!pdpyp) { 1006 return NULL; 1007 } 1008 1009 pdpyp->driMajor = major; 1010 pdpyp->driMinor = minor; 1011 pdpyp->driPatch = patch; 1012 1013 pdpyp->base.destroyDisplay = driDestroyDisplay; 1014 pdpyp->base.createScreen = driCreateScreen; 1015 1016 return &pdpyp->base; 1017} 1018 1019#endif /* GLX_DIRECT_RENDERING */ 1020