dri_glx.c revision 86d98fa4a2dfdae75e6ecd9a7e6e73d4183075a0
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 framebuffer.size = 0; 327 328 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) { 329 ErrorMessageF("XF86DRIOpenConnection failed\n"); 330 goto handle_error; 331 } 332 333 fd = drmOpenOnce(NULL, BusID, &newlyopened); 334 335 Xfree(BusID); /* No longer needed */ 336 337 if (fd < 0) { 338 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd)); 339 goto handle_error; 340 } 341 342 if (drmGetMagic(fd, &magic)) { 343 ErrorMessageF("drmGetMagic failed\n"); 344 goto handle_error; 345 } 346 347 version = drmGetVersion(fd); 348 if (version) { 349 drm_version.major = version->version_major; 350 drm_version.minor = version->version_minor; 351 drm_version.patch = version->version_patchlevel; 352 drmFreeVersion(version); 353 } 354 else { 355 drm_version.major = -1; 356 drm_version.minor = -1; 357 drm_version.patch = -1; 358 } 359 360 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) { 361 ErrorMessageF("XF86DRIAuthConnection failed\n"); 362 goto handle_error; 363 } 364 365 /* Get device name (like "tdfx") and the ddx version numbers. 366 * We'll check the version in each DRI driver's "createNewScreen" 367 * function. */ 368 if (!XF86DRIGetClientDriverName(dpy, scrn, 369 &ddx_version.major, 370 &ddx_version.minor, 371 &ddx_version.patch, &driverName)) { 372 ErrorMessageF("XF86DRIGetClientDriverName failed\n"); 373 goto handle_error; 374 } 375 376 Xfree(driverName); /* No longer needed. */ 377 378 /* 379 * Get device-specific info. pDevPriv will point to a struct 380 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that 381 * has information about the screen size, depth, pitch, ancilliary 382 * buffers, DRM mmap handles, etc. 383 */ 384 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk, 385 &framebuffer.size, &framebuffer.stride, 386 &framebuffer.dev_priv_size, 387 &framebuffer.dev_priv)) { 388 ErrorMessageF("XF86DRIGetDeviceInfo failed"); 389 goto handle_error; 390 } 391 392 framebuffer.width = DisplayWidth(dpy, scrn); 393 framebuffer.height = DisplayHeight(dpy, scrn); 394 395 /* Map the framebuffer region. */ 396 status = drmMap(fd, hFB, framebuffer.size, 397 (drmAddressPtr) & framebuffer.base); 398 if (status != 0) { 399 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status)); 400 goto handle_error; 401 } 402 403 /* Map the SAREA region. Further mmap regions may be setup in 404 * each DRI driver's "createNewScreen" function. 405 */ 406 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA); 407 if (status != 0) { 408 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status)); 409 goto handle_error; 410 } 411 412 psp = (*psc->legacy->createNewScreen) (scrn, 413 &ddx_version, 414 &dri_version, 415 &drm_version, 416 &framebuffer, 417 pSAREA, 418 fd, 419 loader_extensions, 420 &driver_configs, psc); 421 422 if (psp == NULL) { 423 ErrorMessageF("Calling driver entry point failed"); 424 goto handle_error; 425 } 426 427 psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs); 428 psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs); 429 430 psc->driver_configs = driver_configs; 431 432 /* Visuals with depth != screen depth are subject to automatic compositing 433 * in the X server, so DRI1 can't render to them properly. Mark them as 434 * non-conformant to prevent apps from picking them up accidentally. 435 */ 436 for (visual = psc->visuals; visual; visual = visual->next) { 437 XVisualInfo template; 438 XVisualInfo *visuals; 439 int num_visuals; 440 long mask; 441 442 template.visualid = visual->visualID; 443 mask = VisualIDMask; 444 visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals); 445 446 if (visuals) { 447 if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn)) 448 visual->visualRating = GLX_NON_CONFORMANT_CONFIG; 449 450 XFree(visuals); 451 } 452 } 453 454 return psp; 455 456 handle_error: 457 if (pSAREA != MAP_FAILED) 458 drmUnmap(pSAREA, SAREA_MAX); 459 460 if (framebuffer.base != MAP_FAILED) 461 drmUnmap((drmAddress) framebuffer.base, framebuffer.size); 462 463 if (framebuffer.dev_priv != NULL) 464 Xfree(framebuffer.dev_priv); 465 466 if (fd >= 0) 467 drmCloseOnce(fd); 468 469 XF86DRICloseConnection(dpy, scrn); 470 471 ErrorMessageF("reverting to software direct rendering\n"); 472 473 return NULL; 474} 475 476static void 477driDestroyContext(__GLXDRIcontext * context, 478 __GLXscreenConfigs * psc, Display * dpy) 479{ 480 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 481 482 (*psc->core->destroyContext) (pcp->driContext); 483 484 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID); 485 Xfree(pcp); 486} 487 488static Bool 489driBindContext(__GLXDRIcontext * context, 490 __GLXDRIdrawable * draw, __GLXDRIdrawable * read) 491{ 492 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 493 const __DRIcoreExtension *core = pcp->psc->core; 494 495 return (*core->bindContext) (pcp->driContext, 496 draw->driDrawable, read->driDrawable); 497} 498 499static void 500driUnbindContext(__GLXDRIcontext * context) 501{ 502 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 503 const __DRIcoreExtension *core = pcp->psc->core; 504 505 (*core->unbindContext) (pcp->driContext); 506} 507 508static __GLXDRIcontext * 509driCreateContext(__GLXscreenConfigs * psc, 510 const __GLcontextModes * mode, 511 GLXContext gc, GLXContext shareList, int renderType) 512{ 513 __GLXDRIcontextPrivate *pcp, *pcp_shared; 514 drm_context_t hwContext; 515 __DRIcontext *shared = NULL; 516 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode; 517 518 if (!psc || !psc->driScreen) 519 return NULL; 520 521 if (shareList) { 522 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext; 523 shared = pcp_shared->driContext; 524 } 525 526 pcp = Xmalloc(sizeof *pcp); 527 if (pcp == NULL) 528 return NULL; 529 530 pcp->psc = psc; 531 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr, 532 mode->visualID, 533 &pcp->hwContextID, &hwContext)) { 534 Xfree(pcp); 535 return NULL; 536 } 537 538 pcp->driContext = 539 (*psc->legacy->createNewContext) (psc->__driScreen, 540 config->driConfig, 541 renderType, shared, hwContext, pcp); 542 if (pcp->driContext == NULL) { 543 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID); 544 Xfree(pcp); 545 return NULL; 546 } 547 548 pcp->base.destroyContext = driDestroyContext; 549 pcp->base.bindContext = driBindContext; 550 pcp->base.unbindContext = driUnbindContext; 551 552 return &pcp->base; 553} 554 555static void 556driDestroyDrawable(__GLXDRIdrawable * pdraw) 557{ 558 __GLXscreenConfigs *psc = pdraw->psc; 559 560 (*psc->core->destroyDrawable) (pdraw->driDrawable); 561 XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable); 562 Xfree(pdraw); 563} 564 565static __GLXDRIdrawable * 566driCreateDrawable(__GLXscreenConfigs * psc, 567 XID xDrawable, 568 GLXDrawable drawable, const __GLcontextModes * modes) 569{ 570 __GLXDRIdrawable *pdraw; 571 drm_drawable_t hwDrawable; 572 void *empty_attribute_list = NULL; 573 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; 574 575 /* Old dri can't handle GLX 1.3+ drawable constructors. */ 576 if (xDrawable != drawable) 577 return NULL; 578 579 pdraw = Xmalloc(sizeof(*pdraw)); 580 if (!pdraw) 581 return NULL; 582 583 pdraw->drawable = drawable; 584 pdraw->psc = psc; 585 586 if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable)) { 587 Xfree(pdraw); 588 return NULL; 589 } 590 591 /* Create a new drawable */ 592 pdraw->driDrawable = 593 (*psc->legacy->createNewDrawable) (psc->__driScreen, 594 config->driConfig, 595 hwDrawable, 596 GLX_WINDOW_BIT, 597 empty_attribute_list, pdraw); 598 599 if (!pdraw->driDrawable) { 600 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable); 601 Xfree(pdraw); 602 return NULL; 603 } 604 605 pdraw->destroyDrawable = driDestroyDrawable; 606 607 return pdraw; 608} 609 610static int64_t 611driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2, 612 int64_t unused3) 613{ 614 (*pdraw->psc->core->swapBuffers) (pdraw->driDrawable); 615 return 0; 616} 617 618static void 619driCopySubBuffer(__GLXDRIdrawable * pdraw, 620 int x, int y, int width, int height) 621{ 622 (*pdraw->psc->driCopySubBuffer->copySubBuffer) (pdraw->driDrawable, 623 x, y, width, height); 624} 625 626static void 627driDestroyScreen(__GLXscreenConfigs * psc) 628{ 629 /* Free the direct rendering per screen data */ 630 if (psc->__driScreen) 631 (*psc->core->destroyScreen) (psc->__driScreen); 632 psc->__driScreen = NULL; 633 if (psc->driver) 634 dlclose(psc->driver); 635} 636 637static __GLXDRIscreen * 638driCreateScreen(__GLXscreenConfigs * psc, int screen, 639 __GLXdisplayPrivate * priv) 640{ 641 __GLXDRIdisplayPrivate *pdp; 642 __GLXDRIscreen *psp; 643 const __DRIextension **extensions; 644 char *driverName; 645 int i; 646 647 psp = Xcalloc(1, sizeof *psp); 648 if (psp == NULL) 649 return NULL; 650 651 /* Initialize per screen dynamic client GLX extensions */ 652 psc->ext_list_first_time = GL_TRUE; 653 654 if (!driGetDriverName(priv->dpy, screen, &driverName)) { 655 Xfree(psp); 656 return NULL; 657 } 658 659 psc->driver = driOpenDriver(driverName); 660 Xfree(driverName); 661 if (psc->driver == NULL) { 662 Xfree(psp); 663 return NULL; 664 } 665 666 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 667 if (extensions == NULL) { 668 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 669 Xfree(psp); 670 return NULL; 671 } 672 673 for (i = 0; extensions[i]; i++) { 674 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 675 psc->core = (__DRIcoreExtension *) extensions[i]; 676 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0) 677 psc->legacy = (__DRIlegacyExtension *) extensions[i]; 678 } 679 680 if (psc->core == NULL || psc->legacy == NULL) { 681 Xfree(psp); 682 return NULL; 683 } 684 685 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay; 686 psc->__driScreen = CallCreateNewScreen(psc->dpy, screen, psc, pdp); 687 if (psc->__driScreen == NULL) { 688 dlclose(psc->driver); 689 Xfree(psp); 690 return NULL; 691 } 692 693 driBindExtensions(psc); 694 driBindCommonExtensions(psc); 695 696 if (psc->driCopySubBuffer) 697 psp->copySubBuffer = driCopySubBuffer; 698 699 psp->destroyScreen = driDestroyScreen; 700 psp->createContext = driCreateContext; 701 psp->createDrawable = driCreateDrawable; 702 psp->swapBuffers = driSwapBuffers; 703 psp->waitX = NULL; 704 psp->waitGL = NULL; 705 706 return psp; 707} 708 709/* Called from __glXFreeDisplayPrivate. 710 */ 711static void 712driDestroyDisplay(__GLXDRIdisplay * dpy) 713{ 714 Xfree(dpy); 715} 716 717/* 718 * Allocate, initialize and return a __DRIdisplayPrivate object. 719 * This is called from __glXInitialize() when we are given a new 720 * display pointer. 721 */ 722_X_HIDDEN __GLXDRIdisplay * 723driCreateDisplay(Display * dpy) 724{ 725 __GLXDRIdisplayPrivate *pdpyp; 726 int eventBase, errorBase; 727 int major, minor, patch; 728 729 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) { 730 return NULL; 731 } 732 733 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) { 734 return NULL; 735 } 736 737 pdpyp = Xmalloc(sizeof *pdpyp); 738 if (!pdpyp) { 739 return NULL; 740 } 741 742 pdpyp->driMajor = major; 743 pdpyp->driMinor = minor; 744 pdpyp->driPatch = patch; 745 746 pdpyp->base.destroyDisplay = driDestroyDisplay; 747 pdpyp->base.createScreen = driCreateScreen; 748 749 return &pdpyp->base; 750} 751 752#endif /* GLX_DIRECT_RENDERING */ 753