drisw_glx.c revision 2c778375a1356ffb8db1522bc3fc64c568c35cb1
1/* 2 * Copyright 2008 George Sapountzis 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 25 26#include <X11/Xlib.h> 27#include "glxclient.h" 28#include <dlfcn.h> 29#include "dri_common.h" 30 31struct drisw_display 32{ 33 __GLXDRIdisplay base; 34}; 35 36struct drisw_context 37{ 38 struct glx_context base; 39 __DRIcontext *driContext; 40 41}; 42 43struct drisw_screen 44{ 45 struct glx_screen base; 46 47 __DRIscreen *driScreen; 48 __GLXDRIscreen vtable; 49 const __DRIcoreExtension *core; 50 const __DRIswrastExtension *swrast; 51 const __DRItexBufferExtension *texBuffer; 52 53 const __DRIconfig **driver_configs; 54 55 void *driver; 56}; 57 58struct drisw_drawable 59{ 60 __GLXDRIdrawable base; 61 62 GC gc; 63 GC swapgc; 64 65 __DRIdrawable *driDrawable; 66 XVisualInfo *visinfo; 67 XImage *ximage; 68}; 69 70static Bool 71XCreateDrawable(struct drisw_drawable * pdp, 72 Display * dpy, XID drawable, int visualid) 73{ 74 XGCValues gcvalues; 75 long visMask; 76 XVisualInfo visTemp; 77 int num_visuals; 78 79 /* create GC's */ 80 pdp->gc = XCreateGC(dpy, drawable, 0, NULL); 81 pdp->swapgc = XCreateGC(dpy, drawable, 0, NULL); 82 83 gcvalues.function = GXcopy; 84 gcvalues.graphics_exposures = False; 85 XChangeGC(dpy, pdp->gc, GCFunction, &gcvalues); 86 XChangeGC(dpy, pdp->swapgc, GCFunction, &gcvalues); 87 XChangeGC(dpy, pdp->swapgc, GCGraphicsExposures, &gcvalues); 88 89 /* visual */ 90 visTemp.visualid = visualid; 91 visMask = VisualIDMask; 92 pdp->visinfo = XGetVisualInfo(dpy, visMask, &visTemp, &num_visuals); 93 94 if (!pdp->visinfo || num_visuals == 0) 95 return False; 96 97 /* create XImage */ 98 pdp->ximage = XCreateImage(dpy, 99 pdp->visinfo->visual, 100 pdp->visinfo->depth, 101 ZPixmap, 0, /* format, offset */ 102 NULL, /* data */ 103 0, 0, /* width, height */ 104 32, /* bitmap_pad */ 105 0); /* bytes_per_line */ 106 107 /** 108 * swrast does not handle 24-bit depth with 24 bpp, so let X do the 109 * the conversion for us. 110 */ 111 if (pdp->ximage->bits_per_pixel == 24) 112 pdp->ximage->bits_per_pixel = 32; 113 114 return True; 115} 116 117static void 118XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable) 119{ 120 XDestroyImage(pdp->ximage); 121 XFree(pdp->visinfo); 122 123 XFreeGC(dpy, pdp->gc); 124 XFreeGC(dpy, pdp->swapgc); 125} 126 127/** 128 * swrast loader functions 129 */ 130 131static void 132swrastGetDrawableInfo(__DRIdrawable * draw, 133 int *x, int *y, int *w, int *h, 134 void *loaderPrivate) 135{ 136 struct drisw_drawable *pdp = loaderPrivate; 137 __GLXDRIdrawable *pdraw = &(pdp->base); 138 Display *dpy = pdraw->psc->dpy; 139 Drawable drawable; 140 141 Window root; 142 unsigned uw, uh, bw, depth; 143 144 drawable = pdraw->xDrawable; 145 146 XGetGeometry(dpy, drawable, &root, x, y, &uw, &uh, &bw, &depth); 147 *w = uw; 148 *h = uh; 149} 150 151/** 152 * Align renderbuffer pitch. 153 * 154 * This should be chosen by the driver and the loader (libGL, xserver/glx) 155 * should use the driver provided pitch. 156 * 157 * It seems that the xorg loader (that is the xserver loading swrast_dri for 158 * indirect rendering, not client-side libGL) requires that the pitch is 159 * exactly the image width padded to 32 bits. XXX 160 * 161 * The above restriction can probably be overcome by using ScratchPixmap and 162 * CopyArea in the xserver, similar to ShmPutImage, and setting the width of 163 * the scratch pixmap to 'pitch / cpp'. 164 */ 165static inline int 166bytes_per_line(unsigned pitch_bits, unsigned mul) 167{ 168 unsigned mask = mul - 1; 169 170 return ((pitch_bits + mask) & ~mask) / 8; 171} 172 173static void 174swrastPutImage(__DRIdrawable * draw, int op, 175 int x, int y, int w, int h, 176 char *data, void *loaderPrivate) 177{ 178 struct drisw_drawable *pdp = loaderPrivate; 179 __GLXDRIdrawable *pdraw = &(pdp->base); 180 Display *dpy = pdraw->psc->dpy; 181 Drawable drawable; 182 XImage *ximage; 183 GC gc; 184 185 switch (op) { 186 case __DRI_SWRAST_IMAGE_OP_DRAW: 187 gc = pdp->gc; 188 break; 189 case __DRI_SWRAST_IMAGE_OP_SWAP: 190 gc = pdp->swapgc; 191 break; 192 default: 193 return; 194 } 195 196 drawable = pdraw->xDrawable; 197 198 ximage = pdp->ximage; 199 ximage->data = data; 200 ximage->width = w; 201 ximage->height = h; 202 ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32); 203 204 XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h); 205 206 ximage->data = NULL; 207} 208 209static void 210swrastGetImage(__DRIdrawable * read, 211 int x, int y, int w, int h, 212 char *data, void *loaderPrivate) 213{ 214 struct drisw_drawable *prp = loaderPrivate; 215 __GLXDRIdrawable *pread = &(prp->base); 216 Display *dpy = pread->psc->dpy; 217 Drawable readable; 218 XImage *ximage; 219 220 readable = pread->xDrawable; 221 222 ximage = prp->ximage; 223 ximage->data = data; 224 ximage->width = w; 225 ximage->height = h; 226 ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32); 227 228 XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0); 229 230 ximage->data = NULL; 231} 232 233static const __DRIswrastLoaderExtension swrastLoaderExtension = { 234 {__DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION}, 235 swrastGetDrawableInfo, 236 swrastPutImage, 237 swrastGetImage 238}; 239 240static const __DRIextension *loader_extensions[] = { 241 &systemTimeExtension.base, 242 &swrastLoaderExtension.base, 243 NULL 244}; 245 246/** 247 * GLXDRI functions 248 */ 249 250static void 251drisw_destroy_context(struct glx_context *context) 252{ 253 struct drisw_context *pcp = (struct drisw_context *) context; 254 struct drisw_screen *psc = (struct drisw_screen *) context->psc; 255 256 driReleaseDrawables(&pcp->base); 257 258 if (context->extensions) 259 XFree((char *) context->extensions); 260 261 (*psc->core->destroyContext) (pcp->driContext); 262 263 Xfree(pcp); 264} 265 266static int 267drisw_bind_context(struct glx_context *context, struct glx_context *old, 268 GLXDrawable draw, GLXDrawable read) 269{ 270 struct drisw_context *pcp = (struct drisw_context *) context; 271 struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc; 272 struct drisw_drawable *pdraw, *pread; 273 274 pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw); 275 pread = (struct drisw_drawable *) driFetchDrawable(context, read); 276 277 driReleaseDrawables(&pcp->base); 278 279 if (pdraw == NULL || pread == NULL) 280 return GLXBadDrawable; 281 282 if ((*psc->core->bindContext) (pcp->driContext, 283 pdraw->driDrawable, pread->driDrawable)) 284 return Success; 285 286 return GLXBadContext; 287} 288 289static void 290drisw_unbind_context(struct glx_context *context, struct glx_context *new) 291{ 292 struct drisw_context *pcp = (struct drisw_context *) context; 293 struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc; 294 295 (*psc->core->unbindContext) (pcp->driContext); 296} 297 298static void 299drisw_bind_tex_image(Display * dpy, 300 GLXDrawable drawable, 301 int buffer, const int *attrib_list) 302{ 303 struct glx_context *gc = __glXGetCurrentContext(); 304 struct drisw_context *pcp = (struct drisw_context *) gc; 305 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 306 struct drisw_drawable *pdraw = (struct drisw_drawable *) base; 307 struct drisw_screen *psc; 308 309 __glXInitialize(dpy); 310 311 if (pdraw != NULL) { 312 psc = (struct drisw_screen *) base->psc; 313 314 if (!psc->texBuffer) 315 return; 316 317 if (psc->texBuffer->base.version >= 2 && 318 psc->texBuffer->setTexBuffer2 != NULL) { 319 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 320 pdraw->base.textureTarget, 321 pdraw->base.textureFormat, 322 pdraw->driDrawable); 323 } 324 else { 325 (*psc->texBuffer->setTexBuffer) (pcp->driContext, 326 pdraw->base.textureTarget, 327 pdraw->driDrawable); 328 } 329 } 330} 331 332static void 333drisw_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 334{ 335#if __DRI_TEX_BUFFER_VERSION >= 3 336 struct glx_context *gc = __glXGetCurrentContext(); 337 struct dri2_context *pcp = (struct dri2_context *) gc; 338 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 339 struct glx_display *dpyPriv = __glXInitialize(dpy); 340 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 341 struct dri2_screen *psc; 342 343 if (pdraw != NULL) { 344 psc = (struct dri2_screen *) base->psc; 345 346 if (!psc->texBuffer) 347 return; 348 349 if (psc->texBuffer->base.version >= 3 && 350 psc->texBuffer->releaseTexBuffer != NULL) { 351 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 352 pdraw->base.textureTarget, 353 pdraw->driDrawable); 354 } 355 } 356#endif 357} 358 359static const struct glx_context_vtable drisw_context_vtable = { 360 drisw_destroy_context, 361 drisw_bind_context, 362 drisw_unbind_context, 363 NULL, 364 NULL, 365 DRI_glXUseXFont, 366 drisw_bind_tex_image, 367 drisw_release_tex_image, 368 NULL, /* get_proc_address */ 369}; 370 371static struct glx_context * 372drisw_create_context(struct glx_screen *base, 373 struct glx_config *config_base, 374 struct glx_context *shareList, int renderType) 375{ 376 struct drisw_context *pcp, *pcp_shared; 377 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 378 struct drisw_screen *psc = (struct drisw_screen *) base; 379 __DRIcontext *shared = NULL; 380 381 if (!psc->base.driScreen) 382 return NULL; 383 384 if (shareList) { 385 /* If the shareList context is not a DRISW context, we cannot possibly 386 * create a DRISW context that shares it. 387 */ 388 if (shareList->vtable->destroy != drisw_destroy_context) { 389 return NULL; 390 } 391 392 pcp_shared = (struct drisw_context *) shareList; 393 shared = pcp_shared->driContext; 394 } 395 396 pcp = Xmalloc(sizeof *pcp); 397 if (pcp == NULL) 398 return NULL; 399 400 memset(pcp, 0, sizeof *pcp); 401 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 402 Xfree(pcp); 403 return NULL; 404 } 405 406 pcp->driContext = 407 (*psc->core->createNewContext) (psc->driScreen, 408 config->driConfig, shared, pcp); 409 if (pcp->driContext == NULL) { 410 Xfree(pcp); 411 return NULL; 412 } 413 414 pcp->base.vtable = &drisw_context_vtable; 415 416 return &pcp->base; 417} 418 419static struct glx_context * 420drisw_create_context_attribs(struct glx_screen *base, 421 struct glx_config *config_base, 422 struct glx_context *shareList, 423 unsigned num_attribs, 424 const uint32_t *attribs, 425 unsigned *error) 426{ 427 struct drisw_context *pcp, *pcp_shared; 428 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 429 struct drisw_screen *psc = (struct drisw_screen *) base; 430 __DRIcontext *shared = NULL; 431 432 uint32_t minor_ver = 1; 433 uint32_t major_ver = 0; 434 uint32_t flags = 0; 435 unsigned api; 436 uint32_t ctx_attribs[2 * 4]; 437 unsigned num_ctx_attribs = 0; 438 439 if (!psc->base.driScreen) 440 return NULL; 441 442 if (psc->swrast->base.version < 3) 443 return NULL; 444 445 /* Remap the GLX tokens to DRI2 tokens. 446 */ 447 if (!dri2_convert_glx_attribs(num_attribs, attribs, 448 &major_ver, &minor_ver, &flags, &api, 449 error)) 450 return NULL; 451 452 if (shareList) { 453 pcp_shared = (struct drisw_context *) shareList; 454 shared = pcp_shared->driContext; 455 } 456 457 pcp = Xmalloc(sizeof *pcp); 458 if (pcp == NULL) 459 return NULL; 460 461 memset(pcp, 0, sizeof *pcp); 462 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 463 Xfree(pcp); 464 return NULL; 465 } 466 467 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; 468 ctx_attribs[num_ctx_attribs++] = major_ver; 469 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; 470 ctx_attribs[num_ctx_attribs++] = minor_ver; 471 472 if (flags != 0) { 473 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; 474 475 /* The current __DRI_CTX_FLAG_* values are identical to the 476 * GLX_CONTEXT_*_BIT values. 477 */ 478 ctx_attribs[num_ctx_attribs++] = flags; 479 } 480 481 pcp->driContext = 482 (*psc->swrast->createContextAttribs) (psc->driScreen, 483 api, 484 config->driConfig, 485 shared, 486 num_ctx_attribs / 2, 487 ctx_attribs, 488 error, 489 pcp); 490 if (pcp->driContext == NULL) { 491 Xfree(pcp); 492 return NULL; 493 } 494 495 pcp->base.vtable = &drisw_context_vtable; 496 497 return &pcp->base; 498} 499 500static void 501driswDestroyDrawable(__GLXDRIdrawable * pdraw) 502{ 503 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw; 504 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc; 505 506 (*psc->core->destroyDrawable) (pdp->driDrawable); 507 508 XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable); 509 Xfree(pdp); 510} 511 512static __GLXDRIdrawable * 513driswCreateDrawable(struct glx_screen *base, XID xDrawable, 514 GLXDrawable drawable, struct glx_config *modes) 515{ 516 struct drisw_drawable *pdp; 517 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; 518 struct drisw_screen *psc = (struct drisw_screen *) base; 519 Bool ret; 520 const __DRIswrastExtension *swrast = psc->swrast; 521 522 pdp = Xmalloc(sizeof(*pdp)); 523 if (!pdp) 524 return NULL; 525 526 memset(pdp, 0, sizeof *pdp); 527 pdp->base.xDrawable = xDrawable; 528 pdp->base.drawable = drawable; 529 pdp->base.psc = &psc->base; 530 531 ret = XCreateDrawable(pdp, psc->base.dpy, xDrawable, modes->visualID); 532 if (!ret) { 533 Xfree(pdp); 534 return NULL; 535 } 536 537 /* Create a new drawable */ 538 pdp->driDrawable = 539 (*swrast->createNewDrawable) (psc->driScreen, config->driConfig, pdp); 540 541 if (!pdp->driDrawable) { 542 XDestroyDrawable(pdp, psc->base.dpy, xDrawable); 543 Xfree(pdp); 544 return NULL; 545 } 546 547 pdp->base.destroyDrawable = driswDestroyDrawable; 548 549 return &pdp->base; 550} 551 552static int64_t 553driswSwapBuffers(__GLXDRIdrawable * pdraw, 554 int64_t target_msc, int64_t divisor, int64_t remainder) 555{ 556 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw; 557 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc; 558 559 (void) target_msc; 560 (void) divisor; 561 (void) remainder; 562 563 (*psc->core->swapBuffers) (pdp->driDrawable); 564 565 return 0; 566} 567 568static void 569driswDestroyScreen(struct glx_screen *base) 570{ 571 struct drisw_screen *psc = (struct drisw_screen *) base; 572 573 /* Free the direct rendering per screen data */ 574 (*psc->core->destroyScreen) (psc->driScreen); 575 driDestroyConfigs(psc->driver_configs); 576 psc->driScreen = NULL; 577 if (psc->driver) 578 dlclose(psc->driver); 579} 580 581#define SWRAST_DRIVER_NAME "swrast" 582 583static void * 584driOpenSwrast(void) 585{ 586 void *driver = NULL; 587 588 if (driver == NULL) 589 driver = driOpenDriver(SWRAST_DRIVER_NAME); 590 591 return driver; 592} 593 594static const struct glx_screen_vtable drisw_screen_vtable = { 595 drisw_create_context, 596 drisw_create_context_attribs 597}; 598 599static void 600driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions) 601{ 602 int i; 603 604 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 605 606 if (psc->swrast->base.version >= 3) { 607 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context"); 608 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile"); 609 610 /* DRISW version >= 2 implies support for OpenGL ES 2.0. 611 */ 612 __glXEnableDirectExtension(&psc->base, 613 "GLX_EXT_create_context_es2_profile"); 614 } 615 616 /* FIXME: Figure out what other extensions can be ported here from dri2. */ 617 for (i = 0; extensions[i]; i++) { 618 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 619 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 620 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 621 } 622 } 623} 624 625static struct glx_screen * 626driswCreateScreen(int screen, struct glx_display *priv) 627{ 628 __GLXDRIscreen *psp; 629 const __DRIconfig **driver_configs; 630 const __DRIextension **extensions; 631 struct drisw_screen *psc; 632 struct glx_config *configs = NULL, *visuals = NULL; 633 int i; 634 635 psc = Xcalloc(1, sizeof *psc); 636 if (psc == NULL) 637 return NULL; 638 639 memset(psc, 0, sizeof *psc); 640 if (!glx_screen_init(&psc->base, screen, priv)) { 641 Xfree(psc); 642 return NULL; 643 } 644 645 psc->driver = driOpenSwrast(); 646 if (psc->driver == NULL) 647 goto handle_error; 648 649 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 650 if (extensions == NULL) { 651 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 652 goto handle_error; 653 } 654 655 for (i = 0; extensions[i]; i++) { 656 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 657 psc->core = (__DRIcoreExtension *) extensions[i]; 658 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0) 659 psc->swrast = (__DRIswrastExtension *) extensions[i]; 660 } 661 662 if (psc->core == NULL || psc->swrast == NULL) { 663 ErrorMessageF("core dri extension not found\n"); 664 goto handle_error; 665 } 666 667 psc->driScreen = 668 psc->swrast->createNewScreen(screen, loader_extensions, 669 &driver_configs, psc); 670 if (psc->driScreen == NULL) { 671 ErrorMessageF("failed to create dri screen\n"); 672 goto handle_error; 673 } 674 675 extensions = psc->core->getExtensions(psc->driScreen); 676 driswBindExtensions(psc, extensions); 677 678 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); 679 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 680 681 if (!configs || !visuals) 682 goto handle_error; 683 684 glx_config_destroy_list(psc->base.configs); 685 psc->base.configs = configs; 686 glx_config_destroy_list(psc->base.visuals); 687 psc->base.visuals = visuals; 688 689 psc->driver_configs = driver_configs; 690 691 psc->base.vtable = &drisw_screen_vtable; 692 psp = &psc->vtable; 693 psc->base.driScreen = psp; 694 psp->destroyScreen = driswDestroyScreen; 695 psp->createDrawable = driswCreateDrawable; 696 psp->swapBuffers = driswSwapBuffers; 697 698 return &psc->base; 699 700 handle_error: 701 if (configs) 702 glx_config_destroy_list(configs); 703 if (visuals) 704 glx_config_destroy_list(visuals); 705 if (psc->driScreen) 706 psc->core->destroyScreen(psc->driScreen); 707 psc->driScreen = NULL; 708 709 if (psc->driver) 710 dlclose(psc->driver); 711 glx_screen_cleanup(&psc->base); 712 Xfree(psc); 713 714 CriticalErrorMessageF("failed to load driver: %s\n", SWRAST_DRIVER_NAME); 715 716 return NULL; 717} 718 719/* Called from __glXFreeDisplayPrivate. 720 */ 721static void 722driswDestroyDisplay(__GLXDRIdisplay * dpy) 723{ 724 Xfree(dpy); 725} 726 727/* 728 * Allocate, initialize and return a __DRIdisplayPrivate object. 729 * This is called from __glXInitialize() when we are given a new 730 * display pointer. 731 */ 732_X_HIDDEN __GLXDRIdisplay * 733driswCreateDisplay(Display * dpy) 734{ 735 struct drisw_display *pdpyp; 736 737 pdpyp = Xmalloc(sizeof *pdpyp); 738 if (pdpyp == NULL) 739 return NULL; 740 741 pdpyp->base.destroyDisplay = driswDestroyDisplay; 742 pdpyp->base.createScreen = driswCreateScreen; 743 744 return &pdpyp->base; 745} 746 747#endif /* GLX_DIRECT_RENDERING */ 748