dri_glx.c revision 6e8897ff9f90601ebf6eed500ad942c11b54d1f7
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#ifdef GLX_DIRECT_RENDERING 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 50typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate; 51typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate; 52 53struct __GLXDRIdisplayPrivateRec 54{ 55 __GLXDRIdisplay base; 56 57 /* 58 ** XFree86-DRI version information 59 */ 60 int driMajor; 61 int driMinor; 62 int driPatch; 63}; 64 65struct __GLXDRIcontextPrivateRec 66{ 67 __GLXDRIcontext base; 68 __DRIcontext *driContext; 69 XID hwContextID; 70 __GLXscreenConfigs *psc; 71}; 72 73/* 74 * Given a display pointer and screen number, determine the name of 75 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc). 76 * Return True for success, False for failure. 77 */ 78static Bool 79driGetDriverName(Display * dpy, int scrNum, char **driverName) 80{ 81 int directCapable; 82 Bool b; 83 int event, error; 84 int driverMajor, driverMinor, driverPatch; 85 86 *driverName = NULL; 87 88 if (XF86DRIQueryExtension(dpy, &event, &error)) { /* DRI1 */ 89 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) { 90 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n"); 91 return False; 92 } 93 if (!directCapable) { 94 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n"); 95 return False; 96 } 97 98 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor, 99 &driverPatch, driverName); 100 if (!b) { 101 ErrorMessageF("Cannot determine driver name for screen %d\n", 102 scrNum); 103 return False; 104 } 105 106 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n", 107 driverMajor, driverMinor, driverPatch, *driverName, 108 scrNum); 109 110 return True; 111 } 112 else if (DRI2QueryExtension(dpy, &event, &error)) { /* DRI2 */ 113 char *dev; 114 Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev); 115 116 if (ret) 117 Xfree(dev); 118 119 return ret; 120 } 121 122 return False; 123} 124 125/* 126 * Exported function for querying the DRI driver for a given screen. 127 * 128 * The returned char pointer points to a static array that will be 129 * overwritten by subsequent calls. 130 */ 131PUBLIC const char * 132glXGetScreenDriver(Display * dpy, int scrNum) 133{ 134 static char ret[32]; 135 char *driverName; 136 if (driGetDriverName(dpy, scrNum, &driverName)) { 137 int len; 138 if (!driverName) 139 return NULL; 140 len = strlen(driverName); 141 if (len >= 31) 142 return NULL; 143 memcpy(ret, driverName, len + 1); 144 Xfree(driverName); 145 return ret; 146 } 147 return NULL; 148} 149 150/* 151 * Exported function for obtaining a driver's option list (UTF-8 encoded XML). 152 * 153 * The returned char pointer points directly into the driver. Therefore 154 * it should be treated as a constant. 155 * 156 * If the driver was not found or does not support configuration NULL is 157 * returned. 158 * 159 * Note: The driver remains opened after this function returns. 160 */ 161PUBLIC const char * 162glXGetDriverConfig(const char *driverName) 163{ 164 void *handle = driOpenDriver(driverName); 165 if (handle) 166 return dlsym(handle, "__driConfigOptions"); 167 else 168 return NULL; 169} 170 171#ifdef XDAMAGE_1_1_INTERFACE 172 173static GLboolean 174has_damage_post(Display * dpy) 175{ 176 static GLboolean inited = GL_FALSE; 177 static GLboolean has_damage; 178 179 if (!inited) { 180 int major, minor; 181 182 if (XDamageQueryVersion(dpy, &major, &minor) && 183 major == 1 && minor >= 1) { 184 has_damage = GL_TRUE; 185 } 186 else { 187 has_damage = GL_FALSE; 188 } 189 inited = GL_TRUE; 190 } 191 192 return has_damage; 193} 194 195static void 196__glXReportDamage(__DRIdrawable * driDraw, 197 int x, int y, 198 drm_clip_rect_t * rects, int num_rects, 199 GLboolean front_buffer, void *loaderPrivate) 200{ 201 XRectangle *xrects; 202 XserverRegion region; 203 int i; 204 int x_off, y_off; 205 __GLXDRIdrawable *glxDraw = loaderPrivate; 206 __GLXscreenConfigs *psc = glxDraw->psc; 207 Display *dpy = psc->dpy; 208 Drawable drawable; 209 210 if (!has_damage_post(dpy)) 211 return; 212 213 if (front_buffer) { 214 x_off = x; 215 y_off = y; 216 drawable = RootWindow(dpy, psc->scr); 217 } 218 else { 219 x_off = 0; 220 y_off = 0; 221 drawable = glxDraw->xDrawable; 222 } 223 224 xrects = malloc(sizeof(XRectangle) * num_rects); 225 if (xrects == NULL) 226 return; 227 228 for (i = 0; i < num_rects; i++) { 229 xrects[i].x = rects[i].x1 + x_off; 230 xrects[i].y = rects[i].y1 + y_off; 231 xrects[i].width = rects[i].x2 - rects[i].x1; 232 xrects[i].height = rects[i].y2 - rects[i].y1; 233 } 234 region = XFixesCreateRegion(dpy, xrects, num_rects); 235 free(xrects); 236 XDamageAdd(dpy, drawable, region); 237 XFixesDestroyRegion(dpy, region); 238} 239 240static const __DRIdamageExtension damageExtension = { 241 {__DRI_DAMAGE, __DRI_DAMAGE_VERSION}, 242 __glXReportDamage, 243}; 244 245#endif 246 247static GLboolean 248__glXDRIGetDrawableInfo(__DRIdrawable * drawable, 249 unsigned int *index, unsigned int *stamp, 250 int *X, int *Y, int *W, int *H, 251 int *numClipRects, drm_clip_rect_t ** pClipRects, 252 int *backX, int *backY, 253 int *numBackClipRects, 254 drm_clip_rect_t ** pBackClipRects, 255 void *loaderPrivate) 256{ 257 __GLXDRIdrawable *glxDraw = loaderPrivate; 258 __GLXscreenConfigs *psc = glxDraw->psc; 259 Display *dpy = psc->dpy; 260 261 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable, 262 index, stamp, X, Y, W, H, 263 numClipRects, pClipRects, 264 backX, backY, 265 numBackClipRects, pBackClipRects); 266} 267 268static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = { 269 {__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION}, 270 __glXDRIGetDrawableInfo 271}; 272 273static const __DRIextension *loader_extensions[] = { 274 &systemTimeExtension.base, 275 &getDrawableInfoExtension.base, 276#ifdef XDAMAGE_1_1_INTERFACE 277 &damageExtension.base, 278#endif 279 NULL 280}; 281 282/** 283 * Perform the required libGL-side initialization and call the client-side 284 * driver's \c __driCreateNewScreen function. 285 * 286 * \param dpy Display pointer. 287 * \param scrn Screen number on the display. 288 * \param psc DRI screen information. 289 * \param driDpy DRI display information. 290 * \param createNewScreen Pointer to the client-side driver's 291 * \c __driCreateNewScreen function. 292 * \returns A pointer to the \c __DRIscreen structure returned by 293 * the client-side driver on success, or \c NULL on failure. 294 */ 295static void * 296CallCreateNewScreen(Display * dpy, int scrn, __GLXscreenConfigs * psc, 297 __GLXDRIdisplayPrivate * driDpy) 298{ 299 void *psp = NULL; 300 drm_handle_t hSAREA; 301 drmAddress pSAREA = MAP_FAILED; 302 char *BusID; 303 __DRIversion ddx_version; 304 __DRIversion dri_version; 305 __DRIversion drm_version; 306 __DRIframebuffer framebuffer; 307 int fd = -1; 308 int status; 309 310 drm_magic_t magic; 311 drmVersionPtr version; 312 int newlyopened; 313 char *driverName; 314 drm_handle_t hFB; 315 int junk; 316 const __DRIconfig **driver_configs; 317 __GLcontextModes *visual; 318 319 /* DRI protocol version. */ 320 dri_version.major = driDpy->driMajor; 321 dri_version.minor = driDpy->driMinor; 322 dri_version.patch = driDpy->driPatch; 323 324 framebuffer.base = MAP_FAILED; 325 framebuffer.dev_priv = NULL; 326 327 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) { 328 ErrorMessageF("XF86DRIOpenConnection failed\n"); 329 goto handle_error; 330 } 331 332 fd = drmOpenOnce(NULL, BusID, &newlyopened); 333 334 Xfree(BusID); /* No longer needed */ 335 336 if (fd < 0) { 337 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd)); 338 goto handle_error; 339 } 340 341 if (drmGetMagic(fd, &magic)) { 342 ErrorMessageF("drmGetMagic failed\n"); 343 goto handle_error; 344 } 345 346 version = drmGetVersion(fd); 347 if (version) { 348 drm_version.major = version->version_major; 349 drm_version.minor = version->version_minor; 350 drm_version.patch = version->version_patchlevel; 351 drmFreeVersion(version); 352 } 353 else { 354 drm_version.major = -1; 355 drm_version.minor = -1; 356 drm_version.patch = -1; 357 } 358 359 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) { 360 ErrorMessageF("XF86DRIAuthConnection failed\n"); 361 goto handle_error; 362 } 363 364 /* Get device name (like "tdfx") and the ddx version numbers. 365 * We'll check the version in each DRI driver's "createNewScreen" 366 * function. */ 367 if (!XF86DRIGetClientDriverName(dpy, scrn, 368 &ddx_version.major, 369 &ddx_version.minor, 370 &ddx_version.patch, &driverName)) { 371 ErrorMessageF("XF86DRIGetClientDriverName failed\n"); 372 goto handle_error; 373 } 374 375 Xfree(driverName); /* No longer needed. */ 376 377 /* 378 * Get device-specific info. pDevPriv will point to a struct 379 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that 380 * has information about the screen size, depth, pitch, ancilliary 381 * buffers, DRM mmap handles, etc. 382 */ 383 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk, 384 &framebuffer.size, &framebuffer.stride, 385 &framebuffer.dev_priv_size, 386 &framebuffer.dev_priv)) { 387 ErrorMessageF("XF86DRIGetDeviceInfo failed"); 388 goto handle_error; 389 } 390 391 framebuffer.width = DisplayWidth(dpy, scrn); 392 framebuffer.height = DisplayHeight(dpy, scrn); 393 394 /* Map the framebuffer region. */ 395 status = drmMap(fd, hFB, framebuffer.size, 396 (drmAddressPtr) & framebuffer.base); 397 if (status != 0) { 398 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status)); 399 goto handle_error; 400 } 401 402 /* Map the SAREA region. Further mmap regions may be setup in 403 * each DRI driver's "createNewScreen" function. 404 */ 405 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA); 406 if (status != 0) { 407 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status)); 408 goto handle_error; 409 } 410 411 psp = (*psc->legacy->createNewScreen) (scrn, 412 &ddx_version, 413 &dri_version, 414 &drm_version, 415 &framebuffer, 416 pSAREA, 417 fd, 418 loader_extensions, 419 &driver_configs, psc); 420 421 if (psp == NULL) { 422 ErrorMessageF("Calling driver entry point failed"); 423 goto handle_error; 424 } 425 426 psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs); 427 psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs); 428 429 psc->driver_configs = driver_configs; 430 431 /* Visuals with depth != screen depth are subject to automatic compositing 432 * in the X server, so DRI1 can't render to them properly. Mark them as 433 * non-conformant to prevent apps from picking them up accidentally. 434 */ 435 for (visual = psc->visuals; visual; visual = visual->next) { 436 XVisualInfo template; 437 XVisualInfo *visuals; 438 int num_visuals; 439 long mask; 440 441 template.visualid = visual->visualID; 442 mask = VisualIDMask; 443 visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals); 444 445 if (visuals) { 446 if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn)) 447 visual->visualRating = GLX_NON_CONFORMANT_CONFIG; 448 449 XFree(visuals); 450 } 451 } 452 453 return psp; 454 455 handle_error: 456 if (pSAREA != MAP_FAILED) 457 drmUnmap(pSAREA, SAREA_MAX); 458 459 if (framebuffer.base != MAP_FAILED) 460 drmUnmap((drmAddress) framebuffer.base, framebuffer.size); 461 462 if (framebuffer.dev_priv != NULL) 463 Xfree(framebuffer.dev_priv); 464 465 if (fd >= 0) 466 drmCloseOnce(fd); 467 468 XF86DRICloseConnection(dpy, scrn); 469 470 ErrorMessageF("reverting to software direct rendering\n"); 471 472 return NULL; 473} 474 475static void 476driDestroyContext(__GLXDRIcontext * context, 477 __GLXscreenConfigs * psc, Display * dpy) 478{ 479 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 480 481 (*psc->core->destroyContext) (pcp->driContext); 482 483 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID); 484 Xfree(pcp); 485} 486 487static Bool 488driBindContext(__GLXDRIcontext * context, 489 __GLXDRIdrawable * draw, __GLXDRIdrawable * read) 490{ 491 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 492 const __DRIcoreExtension *core = pcp->psc->core; 493 494 return (*core->bindContext) (pcp->driContext, 495 draw->driDrawable, read->driDrawable); 496} 497 498static void 499driUnbindContext(__GLXDRIcontext * context) 500{ 501 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 502 const __DRIcoreExtension *core = pcp->psc->core; 503 504 (*core->unbindContext) (pcp->driContext); 505} 506 507static __GLXDRIcontext * 508driCreateContext(__GLXscreenConfigs * psc, 509 const __GLcontextModes * mode, 510 GLXContext gc, GLXContext shareList, int renderType) 511{ 512 __GLXDRIcontextPrivate *pcp, *pcp_shared; 513 drm_context_t hwContext; 514 __DRIcontext *shared = NULL; 515 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode; 516 517 if (!psc || !psc->driScreen) 518 return NULL; 519 520 if (shareList) { 521 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext; 522 shared = pcp_shared->driContext; 523 } 524 525 pcp = Xmalloc(sizeof *pcp); 526 if (pcp == NULL) 527 return NULL; 528 529 pcp->psc = psc; 530 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr, 531 mode->visualID, 532 &pcp->hwContextID, &hwContext)) { 533 Xfree(pcp); 534 return NULL; 535 } 536 537 pcp->driContext = 538 (*psc->legacy->createNewContext) (psc->__driScreen, 539 config->driConfig, 540 renderType, shared, hwContext, pcp); 541 if (pcp->driContext == NULL) { 542 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID); 543 Xfree(pcp); 544 return NULL; 545 } 546 547 pcp->base.destroyContext = driDestroyContext; 548 pcp->base.bindContext = driBindContext; 549 pcp->base.unbindContext = driUnbindContext; 550 551 return &pcp->base; 552} 553 554static void 555driDestroyDrawable(__GLXDRIdrawable * pdraw) 556{ 557 __GLXscreenConfigs *psc = pdraw->psc; 558 559 (*psc->core->destroyDrawable) (pdraw->driDrawable); 560 XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable); 561 Xfree(pdraw); 562} 563 564static __GLXDRIdrawable * 565driCreateDrawable(__GLXscreenConfigs * psc, 566 XID xDrawable, 567 GLXDrawable drawable, const __GLcontextModes * modes) 568{ 569 __GLXDRIdrawable *pdraw; 570 drm_drawable_t hwDrawable; 571 void *empty_attribute_list = NULL; 572 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; 573 574 /* Old dri can't handle GLX 1.3+ drawable constructors. */ 575 if (xDrawable != drawable) 576 return NULL; 577 578 pdraw = Xmalloc(sizeof(*pdraw)); 579 if (!pdraw) 580 return NULL; 581 582 pdraw->drawable = drawable; 583 pdraw->psc = psc; 584 585 if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable)) { 586 Xfree(pdraw); 587 return NULL; 588 } 589 590 /* Create a new drawable */ 591 pdraw->driDrawable = 592 (*psc->legacy->createNewDrawable) (psc->__driScreen, 593 config->driConfig, 594 hwDrawable, 595 GLX_WINDOW_BIT, 596 empty_attribute_list, pdraw); 597 598 if (!pdraw->driDrawable) { 599 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable); 600 Xfree(pdraw); 601 return NULL; 602 } 603 604 pdraw->destroyDrawable = driDestroyDrawable; 605 606 return pdraw; 607} 608 609static int64_t 610driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2, 611 int64_t unused3) 612{ 613 (*pdraw->psc->core->swapBuffers) (pdraw->driDrawable); 614 return 0; 615} 616 617static void 618driCopySubBuffer(__GLXDRIdrawable * pdraw, 619 int x, int y, int width, int height) 620{ 621 (*pdraw->psc->driCopySubBuffer->copySubBuffer) (pdraw->driDrawable, 622 x, y, width, height); 623} 624 625static void 626driDestroyScreen(__GLXscreenConfigs * psc) 627{ 628 /* Free the direct rendering per screen data */ 629 if (psc->__driScreen) 630 (*psc->core->destroyScreen) (psc->__driScreen); 631 psc->__driScreen = NULL; 632 if (psc->driver) 633 dlclose(psc->driver); 634} 635 636static __GLXDRIscreen * 637driCreateScreen(__GLXscreenConfigs * psc, int screen, 638 __GLXdisplayPrivate * priv) 639{ 640 __GLXDRIdisplayPrivate *pdp; 641 __GLXDRIscreen *psp; 642 const __DRIextension **extensions; 643 char *driverName; 644 int i; 645 646 psp = Xcalloc(1, sizeof *psp); 647 if (psp == NULL) 648 return NULL; 649 650 /* Initialize per screen dynamic client GLX extensions */ 651 psc->ext_list_first_time = GL_TRUE; 652 653 if (!driGetDriverName(priv->dpy, screen, &driverName)) { 654 Xfree(psp); 655 return NULL; 656 } 657 658 psc->driver = driOpenDriver(driverName); 659 Xfree(driverName); 660 if (psc->driver == NULL) { 661 Xfree(psp); 662 return NULL; 663 } 664 665 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 666 if (extensions == NULL) { 667 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 668 Xfree(psp); 669 return NULL; 670 } 671 672 for (i = 0; extensions[i]; i++) { 673 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 674 psc->core = (__DRIcoreExtension *) extensions[i]; 675 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0) 676 psc->legacy = (__DRIlegacyExtension *) extensions[i]; 677 } 678 679 if (psc->core == NULL || psc->legacy == NULL) { 680 Xfree(psp); 681 return NULL; 682 } 683 684 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay; 685 psc->__driScreen = CallCreateNewScreen(psc->dpy, screen, psc, pdp); 686 if (psc->__driScreen == NULL) { 687 dlclose(psc->driver); 688 Xfree(psp); 689 return NULL; 690 } 691 692 driBindExtensions(psc); 693 driBindCommonExtensions(psc); 694 695 if (psc->driCopySubBuffer) 696 psp->copySubBuffer = driCopySubBuffer; 697 698 psp->destroyScreen = driDestroyScreen; 699 psp->createContext = driCreateContext; 700 psp->createDrawable = driCreateDrawable; 701 psp->swapBuffers = driSwapBuffers; 702 psp->waitX = NULL; 703 psp->waitGL = NULL; 704 705 return psp; 706} 707 708/* Called from __glXFreeDisplayPrivate. 709 */ 710static void 711driDestroyDisplay(__GLXDRIdisplay * dpy) 712{ 713 Xfree(dpy); 714} 715 716/* 717 * Allocate, initialize and return a __DRIdisplayPrivate object. 718 * This is called from __glXInitialize() when we are given a new 719 * display pointer. 720 */ 721_X_HIDDEN __GLXDRIdisplay * 722driCreateDisplay(Display * dpy) 723{ 724 __GLXDRIdisplayPrivate *pdpyp; 725 int eventBase, errorBase; 726 int major, minor, patch; 727 728 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) { 729 return NULL; 730 } 731 732 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) { 733 return NULL; 734 } 735 736 pdpyp = Xmalloc(sizeof *pdpyp); 737 if (!pdpyp) { 738 return NULL; 739 } 740 741 pdpyp->driMajor = major; 742 pdpyp->driMinor = minor; 743 pdpyp->driPatch = patch; 744 745 pdpyp->base.destroyDisplay = driDestroyDisplay; 746 pdpyp->base.createScreen = driCreateScreen; 747 748 return &pdpyp->base; 749} 750 751#endif /* GLX_DIRECT_RENDERING */ 752