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#include "drisw_priv.h" 31#include <X11/extensions/shmproto.h> 32#include <assert.h> 33 34static Bool 35XCreateGCs(struct drisw_drawable * pdp, 36 Display * dpy, XID drawable, int visualid) 37{ 38 XGCValues gcvalues; 39 long visMask; 40 XVisualInfo visTemp; 41 int num_visuals; 42 43 /* create GC's */ 44 pdp->gc = XCreateGC(dpy, drawable, 0, NULL); 45 pdp->swapgc = XCreateGC(dpy, drawable, 0, NULL); 46 47 gcvalues.function = GXcopy; 48 gcvalues.graphics_exposures = False; 49 XChangeGC(dpy, pdp->gc, GCFunction, &gcvalues); 50 XChangeGC(dpy, pdp->swapgc, GCFunction, &gcvalues); 51 XChangeGC(dpy, pdp->swapgc, GCGraphicsExposures, &gcvalues); 52 53 /* visual */ 54 visTemp.visualid = visualid; 55 visMask = VisualIDMask; 56 pdp->visinfo = XGetVisualInfo(dpy, visMask, &visTemp, &num_visuals); 57 58 if (!pdp->visinfo || num_visuals == 0) 59 return False; 60 61 return True; 62} 63 64static int xshm_error = 0; 65static int xshm_opcode = -1; 66 67/** 68 * Catches potential Xlib errors. 69 */ 70static int 71handle_xerror(Display *dpy, XErrorEvent *event) 72{ 73 (void) dpy; 74 75 assert(xshm_opcode != -1); 76 if (event->request_code != xshm_opcode) 77 return 0; 78 79 xshm_error = event->error_code; 80 return 0; 81} 82 83static Bool 84XCreateDrawable(struct drisw_drawable * pdp, int shmid, Display * dpy) 85{ 86 if (pdp->ximage) { 87 XDestroyImage(pdp->ximage); 88 pdp->ximage = NULL; 89 } 90 91 if (!xshm_error && shmid >= 0) { 92 pdp->shminfo.shmid = shmid; 93 pdp->ximage = XShmCreateImage(dpy, 94 pdp->visinfo->visual, 95 pdp->visinfo->depth, 96 ZPixmap, /* format */ 97 NULL, /* data */ 98 &pdp->shminfo, /* shminfo */ 99 0, 0); /* width, height */ 100 if (pdp->ximage != NULL) { 101 int (*old_handler)(Display *, XErrorEvent *); 102 103 /* dispatch pending errors */ 104 XSync(dpy, False); 105 106 old_handler = XSetErrorHandler(handle_xerror); 107 /* This may trigger the X protocol error we're ready to catch: */ 108 XShmAttach(dpy, &pdp->shminfo); 109 XSync(dpy, False); 110 111 if (xshm_error) { 112 /* we are on a remote display, this error is normal, don't print it */ 113 XDestroyImage(pdp->ximage); 114 pdp->ximage = NULL; 115 } 116 117 (void) XSetErrorHandler(old_handler); 118 } 119 } 120 121 if (pdp->ximage == NULL) { 122 pdp->shminfo.shmid = -1; 123 pdp->ximage = XCreateImage(dpy, 124 pdp->visinfo->visual, 125 pdp->visinfo->depth, 126 ZPixmap, 0, /* format, offset */ 127 NULL, /* data */ 128 0, 0, /* width, height */ 129 32, /* bitmap_pad */ 130 0); /* bytes_per_line */ 131 } 132 133 /** 134 * swrast does not handle 24-bit depth with 24 bpp, so let X do the 135 * the conversion for us. 136 */ 137 if (pdp->ximage->bits_per_pixel == 24) 138 pdp->ximage->bits_per_pixel = 32; 139 140 return True; 141} 142 143static void 144XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable) 145{ 146 if (pdp->ximage) 147 XDestroyImage(pdp->ximage); 148 149 if (pdp->shminfo.shmid > 0) 150 XShmDetach(dpy, &pdp->shminfo); 151 152 free(pdp->visinfo); 153 154 XFreeGC(dpy, pdp->gc); 155 XFreeGC(dpy, pdp->swapgc); 156} 157 158/** 159 * swrast loader functions 160 */ 161 162static void 163swrastGetDrawableInfo(__DRIdrawable * draw, 164 int *x, int *y, int *w, int *h, 165 void *loaderPrivate) 166{ 167 struct drisw_drawable *pdp = loaderPrivate; 168 __GLXDRIdrawable *pdraw = &(pdp->base); 169 Display *dpy = pdraw->psc->dpy; 170 Drawable drawable; 171 172 Window root; 173 unsigned uw, uh, bw, depth; 174 175 drawable = pdraw->xDrawable; 176 177 XGetGeometry(dpy, drawable, &root, x, y, &uw, &uh, &bw, &depth); 178 *w = uw; 179 *h = uh; 180} 181 182/** 183 * Align renderbuffer pitch. 184 * 185 * This should be chosen by the driver and the loader (libGL, xserver/glx) 186 * should use the driver provided pitch. 187 * 188 * It seems that the xorg loader (that is the xserver loading swrast_dri for 189 * indirect rendering, not client-side libGL) requires that the pitch is 190 * exactly the image width padded to 32 bits. XXX 191 * 192 * The above restriction can probably be overcome by using ScratchPixmap and 193 * CopyArea in the xserver, similar to ShmPutImage, and setting the width of 194 * the scratch pixmap to 'pitch / cpp'. 195 */ 196static inline int 197bytes_per_line(unsigned pitch_bits, unsigned mul) 198{ 199 unsigned mask = mul - 1; 200 201 return ((pitch_bits + mask) & ~mask) / 8; 202} 203 204static void 205swrastXPutImage(__DRIdrawable * draw, int op, 206 int srcx, int srcy, int x, int y, 207 int w, int h, int stride, 208 int shmid, char *data, void *loaderPrivate) 209{ 210 struct drisw_drawable *pdp = loaderPrivate; 211 __GLXDRIdrawable *pdraw = &(pdp->base); 212 Display *dpy = pdraw->psc->dpy; 213 Drawable drawable; 214 XImage *ximage; 215 GC gc; 216 217 if (!pdp->ximage || shmid != pdp->shminfo.shmid) { 218 if (!XCreateDrawable(pdp, shmid, dpy)) 219 return; 220 } 221 222 switch (op) { 223 case __DRI_SWRAST_IMAGE_OP_DRAW: 224 gc = pdp->gc; 225 break; 226 case __DRI_SWRAST_IMAGE_OP_SWAP: 227 gc = pdp->swapgc; 228 break; 229 default: 230 return; 231 } 232 233 drawable = pdraw->xDrawable; 234 ximage = pdp->ximage; 235 ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32); 236 ximage->data = data; 237 238 if (pdp->shminfo.shmid >= 0) { 239 ximage->width = ximage->bytes_per_line / ((ximage->bits_per_pixel + 7)/ 8); 240 ximage->height = h; 241 XShmPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h, False); 242 XSync(dpy, False); 243 } else { 244 ximage->width = w; 245 ximage->height = h; 246 XPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h); 247 } 248 ximage->data = NULL; 249} 250 251static void 252swrastPutImageShm(__DRIdrawable * draw, int op, 253 int x, int y, int w, int h, int stride, 254 int shmid, char *shmaddr, unsigned offset, 255 void *loaderPrivate) 256{ 257 struct drisw_drawable *pdp = loaderPrivate; 258 259 pdp->shminfo.shmaddr = shmaddr; 260 swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, shmid, 261 shmaddr + offset, loaderPrivate); 262} 263 264static void 265swrastPutImageShm2(__DRIdrawable * draw, int op, 266 int x, int y, 267 int w, int h, int stride, 268 int shmid, char *shmaddr, unsigned offset, 269 void *loaderPrivate) 270{ 271 struct drisw_drawable *pdp = loaderPrivate; 272 273 pdp->shminfo.shmaddr = shmaddr; 274 swrastXPutImage(draw, op, x, 0, x, y, w, h, stride, shmid, 275 shmaddr + offset, loaderPrivate); 276} 277 278static void 279swrastPutImage2(__DRIdrawable * draw, int op, 280 int x, int y, int w, int h, int stride, 281 char *data, void *loaderPrivate) 282{ 283 swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, -1, 284 data, loaderPrivate); 285} 286 287static void 288swrastPutImage(__DRIdrawable * draw, int op, 289 int x, int y, int w, int h, 290 char *data, void *loaderPrivate) 291{ 292 swrastXPutImage(draw, op, 0, 0, x, y, w, h, 0, -1, 293 data, loaderPrivate); 294} 295 296static void 297swrastGetImage2(__DRIdrawable * read, 298 int x, int y, int w, int h, int stride, 299 char *data, void *loaderPrivate) 300{ 301 struct drisw_drawable *prp = loaderPrivate; 302 __GLXDRIdrawable *pread = &(prp->base); 303 Display *dpy = pread->psc->dpy; 304 Drawable readable; 305 XImage *ximage; 306 307 if (!prp->ximage || prp->shminfo.shmid >= 0) { 308 if (!XCreateDrawable(prp, -1, dpy)) 309 return; 310 } 311 312 readable = pread->xDrawable; 313 314 ximage = prp->ximage; 315 ximage->data = data; 316 ximage->width = w; 317 ximage->height = h; 318 ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32); 319 320 XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0); 321 322 ximage->data = NULL; 323} 324 325static void 326swrastGetImage(__DRIdrawable * read, 327 int x, int y, int w, int h, 328 char *data, void *loaderPrivate) 329{ 330 swrastGetImage2(read, x, y, w, h, 0, data, loaderPrivate); 331} 332 333static void 334swrastGetImageShm(__DRIdrawable * read, 335 int x, int y, int w, int h, 336 int shmid, void *loaderPrivate) 337{ 338 struct drisw_drawable *prp = loaderPrivate; 339 __GLXDRIdrawable *pread = &(prp->base); 340 Display *dpy = pread->psc->dpy; 341 Drawable readable; 342 XImage *ximage; 343 344 if (!prp->ximage || shmid != prp->shminfo.shmid) { 345 if (!XCreateDrawable(prp, shmid, dpy)) 346 return; 347 } 348 readable = pread->xDrawable; 349 350 ximage = prp->ximage; 351 ximage->data = prp->shminfo.shmaddr; /* no offset */ 352 ximage->width = w; 353 ximage->height = h; 354 ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32); 355 356 XShmGetImage(dpy, readable, ximage, x, y, ~0L); 357} 358 359static const __DRIswrastLoaderExtension swrastLoaderExtension_shm = { 360 .base = {__DRI_SWRAST_LOADER, 5 }, 361 362 .getDrawableInfo = swrastGetDrawableInfo, 363 .putImage = swrastPutImage, 364 .getImage = swrastGetImage, 365 .putImage2 = swrastPutImage2, 366 .getImage2 = swrastGetImage2, 367 .putImageShm = swrastPutImageShm, 368 .getImageShm = swrastGetImageShm, 369 .putImageShm2 = swrastPutImageShm2, 370}; 371 372static const __DRIextension *loader_extensions_shm[] = { 373 &swrastLoaderExtension_shm.base, 374 NULL 375}; 376 377static const __DRIswrastLoaderExtension swrastLoaderExtension = { 378 .base = {__DRI_SWRAST_LOADER, 3 }, 379 380 .getDrawableInfo = swrastGetDrawableInfo, 381 .putImage = swrastPutImage, 382 .getImage = swrastGetImage, 383 .putImage2 = swrastPutImage2, 384 .getImage2 = swrastGetImage2, 385}; 386 387static const __DRIextension *loader_extensions_noshm[] = { 388 &swrastLoaderExtension.base, 389 NULL 390}; 391 392/** 393 * GLXDRI functions 394 */ 395 396static void 397drisw_destroy_context(struct glx_context *context) 398{ 399 struct drisw_context *pcp = (struct drisw_context *) context; 400 struct drisw_screen *psc = (struct drisw_screen *) context->psc; 401 402 driReleaseDrawables(&pcp->base); 403 404 free((char *) context->extensions); 405 406 (*psc->core->destroyContext) (pcp->driContext); 407 408 free(pcp); 409} 410 411static int 412drisw_bind_context(struct glx_context *context, struct glx_context *old, 413 GLXDrawable draw, GLXDrawable read) 414{ 415 struct drisw_context *pcp = (struct drisw_context *) context; 416 struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc; 417 struct drisw_drawable *pdraw, *pread; 418 419 pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw); 420 pread = (struct drisw_drawable *) driFetchDrawable(context, read); 421 422 driReleaseDrawables(&pcp->base); 423 424 if ((*psc->core->bindContext) (pcp->driContext, 425 pdraw ? pdraw->driDrawable : NULL, 426 pread ? pread->driDrawable : NULL)) 427 return Success; 428 429 return GLXBadContext; 430} 431 432static void 433drisw_unbind_context(struct glx_context *context, struct glx_context *new) 434{ 435 struct drisw_context *pcp = (struct drisw_context *) context; 436 struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc; 437 438 (*psc->core->unbindContext) (pcp->driContext); 439} 440 441static void 442drisw_bind_tex_image(Display * dpy, 443 GLXDrawable drawable, 444 int buffer, const int *attrib_list) 445{ 446 struct glx_context *gc = __glXGetCurrentContext(); 447 struct drisw_context *pcp = (struct drisw_context *) gc; 448 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 449 struct drisw_drawable *pdraw = (struct drisw_drawable *) base; 450 struct drisw_screen *psc; 451 452 __glXInitialize(dpy); 453 454 if (pdraw != NULL) { 455 psc = (struct drisw_screen *) base->psc; 456 457 if (!psc->texBuffer) 458 return; 459 460 if (psc->texBuffer->base.version >= 2 && 461 psc->texBuffer->setTexBuffer2 != NULL) { 462 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 463 pdraw->base.textureTarget, 464 pdraw->base.textureFormat, 465 pdraw->driDrawable); 466 } 467 else { 468 (*psc->texBuffer->setTexBuffer) (pcp->driContext, 469 pdraw->base.textureTarget, 470 pdraw->driDrawable); 471 } 472 } 473} 474 475static void 476drisw_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 477{ 478 struct glx_context *gc = __glXGetCurrentContext(); 479 struct drisw_context *pcp = (struct drisw_context *) gc; 480 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 481 struct glx_display *dpyPriv = __glXInitialize(dpy); 482 struct drisw_drawable *pdraw = (struct drisw_drawable *) base; 483 struct drisw_screen *psc; 484 485 if (dpyPriv != NULL && pdraw != NULL) { 486 psc = (struct drisw_screen *) base->psc; 487 488 if (!psc->texBuffer) 489 return; 490 491 if (psc->texBuffer->base.version >= 3 && 492 psc->texBuffer->releaseTexBuffer != NULL) { 493 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 494 pdraw->base.textureTarget, 495 pdraw->driDrawable); 496 } 497 } 498} 499 500static const struct glx_context_vtable drisw_context_vtable = { 501 .destroy = drisw_destroy_context, 502 .bind = drisw_bind_context, 503 .unbind = drisw_unbind_context, 504 .wait_gl = NULL, 505 .wait_x = NULL, 506 .use_x_font = DRI_glXUseXFont, 507 .bind_tex_image = drisw_bind_tex_image, 508 .release_tex_image = drisw_release_tex_image, 509 .get_proc_address = NULL, 510}; 511 512static struct glx_context * 513drisw_create_context(struct glx_screen *base, 514 struct glx_config *config_base, 515 struct glx_context *shareList, int renderType) 516{ 517 struct drisw_context *pcp, *pcp_shared; 518 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 519 struct drisw_screen *psc = (struct drisw_screen *) base; 520 __DRIcontext *shared = NULL; 521 522 if (!psc->base.driScreen) 523 return NULL; 524 525 /* Check the renderType value */ 526 if (!validate_renderType_against_config(config_base, renderType)) 527 return NULL; 528 529 if (shareList) { 530 /* If the shareList context is not a DRISW context, we cannot possibly 531 * create a DRISW context that shares it. 532 */ 533 if (shareList->vtable->destroy != drisw_destroy_context) { 534 return NULL; 535 } 536 537 pcp_shared = (struct drisw_context *) shareList; 538 shared = pcp_shared->driContext; 539 } 540 541 pcp = calloc(1, sizeof *pcp); 542 if (pcp == NULL) 543 return NULL; 544 545 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 546 free(pcp); 547 return NULL; 548 } 549 550 pcp->base.renderType = renderType; 551 552 pcp->driContext = 553 (*psc->core->createNewContext) (psc->driScreen, 554 config->driConfig, shared, pcp); 555 if (pcp->driContext == NULL) { 556 free(pcp); 557 return NULL; 558 } 559 560 pcp->base.vtable = &drisw_context_vtable; 561 562 return &pcp->base; 563} 564 565static struct glx_context * 566drisw_create_context_attribs(struct glx_screen *base, 567 struct glx_config *config_base, 568 struct glx_context *shareList, 569 unsigned num_attribs, 570 const uint32_t *attribs, 571 unsigned *error) 572{ 573 struct drisw_context *pcp, *pcp_shared; 574 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 575 struct drisw_screen *psc = (struct drisw_screen *) base; 576 __DRIcontext *shared = NULL; 577 578 uint32_t minor_ver; 579 uint32_t major_ver; 580 uint32_t renderType; 581 uint32_t flags; 582 unsigned api; 583 int reset; 584 int release; 585 uint32_t ctx_attribs[2 * 5]; 586 unsigned num_ctx_attribs = 0; 587 588 if (!psc->base.driScreen) 589 return NULL; 590 591 if (psc->swrast->base.version < 3) 592 return NULL; 593 594 /* Remap the GLX tokens to DRI2 tokens. 595 */ 596 if (!dri2_convert_glx_attribs(num_attribs, attribs, 597 &major_ver, &minor_ver, &renderType, &flags, 598 &api, &reset, &release, error)) 599 return NULL; 600 601 if (!dri2_check_no_error(flags, shareList, major_ver, error)) 602 return NULL; 603 604 /* Check the renderType value */ 605 if (!validate_renderType_against_config(config_base, renderType)) { 606 return NULL; 607 } 608 609 if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) 610 return NULL; 611 612 if (release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH && 613 release != __DRI_CTX_RELEASE_BEHAVIOR_NONE) 614 return NULL; 615 616 if (shareList) { 617 pcp_shared = (struct drisw_context *) shareList; 618 shared = pcp_shared->driContext; 619 } 620 621 pcp = calloc(1, sizeof *pcp); 622 if (pcp == NULL) 623 return NULL; 624 625 if (!glx_context_init(&pcp->base, &psc->base, config_base)) { 626 free(pcp); 627 return NULL; 628 } 629 630 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; 631 ctx_attribs[num_ctx_attribs++] = major_ver; 632 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; 633 ctx_attribs[num_ctx_attribs++] = minor_ver; 634 if (release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) { 635 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR; 636 ctx_attribs[num_ctx_attribs++] = release; 637 } 638 639 if (flags != 0) { 640 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; 641 642 /* The current __DRI_CTX_FLAG_* values are identical to the 643 * GLX_CONTEXT_*_BIT values. 644 */ 645 ctx_attribs[num_ctx_attribs++] = flags; 646 647 if (flags & __DRI_CTX_FLAG_NO_ERROR) 648 pcp->base.noError = GL_TRUE; 649 } 650 651 pcp->base.renderType = renderType; 652 653 pcp->driContext = 654 (*psc->swrast->createContextAttribs) (psc->driScreen, 655 api, 656 config ? config->driConfig : 0, 657 shared, 658 num_ctx_attribs / 2, 659 ctx_attribs, 660 error, 661 pcp); 662 if (pcp->driContext == NULL) { 663 free(pcp); 664 return NULL; 665 } 666 667 pcp->base.vtable = &drisw_context_vtable; 668 669 return &pcp->base; 670} 671 672static void 673driswDestroyDrawable(__GLXDRIdrawable * pdraw) 674{ 675 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw; 676 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc; 677 678 (*psc->core->destroyDrawable) (pdp->driDrawable); 679 680 XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable); 681 free(pdp); 682} 683 684static __GLXDRIdrawable * 685driswCreateDrawable(struct glx_screen *base, XID xDrawable, 686 GLXDrawable drawable, struct glx_config *modes) 687{ 688 struct drisw_drawable *pdp; 689 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; 690 struct drisw_screen *psc = (struct drisw_screen *) base; 691 Bool ret; 692 const __DRIswrastExtension *swrast = psc->swrast; 693 694 pdp = calloc(1, sizeof(*pdp)); 695 if (!pdp) 696 return NULL; 697 698 pdp->base.xDrawable = xDrawable; 699 pdp->base.drawable = drawable; 700 pdp->base.psc = &psc->base; 701 702 ret = XCreateGCs(pdp, psc->base.dpy, xDrawable, modes->visualID); 703 if (!ret) { 704 free(pdp); 705 return NULL; 706 } 707 708 /* Create a new drawable */ 709 pdp->driDrawable = 710 (*swrast->createNewDrawable) (psc->driScreen, config->driConfig, pdp); 711 712 if (!pdp->driDrawable) { 713 XDestroyDrawable(pdp, psc->base.dpy, xDrawable); 714 free(pdp); 715 return NULL; 716 } 717 718 pdp->base.destroyDrawable = driswDestroyDrawable; 719 720 return &pdp->base; 721} 722 723static int64_t 724driswSwapBuffers(__GLXDRIdrawable * pdraw, 725 int64_t target_msc, int64_t divisor, int64_t remainder, 726 Bool flush) 727{ 728 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw; 729 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc; 730 731 (void) target_msc; 732 (void) divisor; 733 (void) remainder; 734 735 if (flush) { 736 glFlush(); 737 } 738 739 (*psc->core->swapBuffers) (pdp->driDrawable); 740 741 return 0; 742} 743 744static void 745driswCopySubBuffer(__GLXDRIdrawable * pdraw, 746 int x, int y, int width, int height, Bool flush) 747{ 748 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw; 749 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc; 750 751 if (flush) { 752 glFlush(); 753 } 754 755 (*psc->copySubBuffer->copySubBuffer) (pdp->driDrawable, 756 x, y, width, height); 757} 758 759static void 760driswDestroyScreen(struct glx_screen *base) 761{ 762 struct drisw_screen *psc = (struct drisw_screen *) base; 763 764 /* Free the direct rendering per screen data */ 765 (*psc->core->destroyScreen) (psc->driScreen); 766 driDestroyConfigs(psc->driver_configs); 767 psc->driScreen = NULL; 768 if (psc->driver) 769 dlclose(psc->driver); 770 free(psc); 771} 772 773#define SWRAST_DRIVER_NAME "swrast" 774 775static const struct glx_screen_vtable drisw_screen_vtable = { 776 .create_context = drisw_create_context, 777 .create_context_attribs = drisw_create_context_attribs, 778 .query_renderer_integer = drisw_query_renderer_integer, 779 .query_renderer_string = drisw_query_renderer_string, 780}; 781 782static void 783driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions) 784{ 785 int i; 786 787 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 788 789 if (psc->swrast->base.version >= 3) { 790 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context"); 791 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile"); 792 793 /* DRISW version >= 2 implies support for OpenGL ES. 794 */ 795 __glXEnableDirectExtension(&psc->base, 796 "GLX_EXT_create_context_es_profile"); 797 __glXEnableDirectExtension(&psc->base, 798 "GLX_EXT_create_context_es2_profile"); 799 } 800 801 if (psc->copySubBuffer) 802 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 803 804 /* FIXME: Figure out what other extensions can be ported here from dri2. */ 805 for (i = 0; extensions[i]; i++) { 806 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 807 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 808 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 809 } 810 /* DRISW version 3 is also required because GLX_MESA_query_renderer 811 * requires GLX_ARB_create_context_profile. 812 */ 813 if (psc->swrast->base.version >= 3 814 && strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) { 815 psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i]; 816 __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer"); 817 } 818 if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) { 819 __glXEnableDirectExtension(&psc->base, 820 "GLX_ARB_context_flush_control"); 821 } 822 } 823} 824 825static int 826check_xshm(Display *dpy) 827{ 828 int (*old_handler)(Display *, XErrorEvent *); 829 830 int ignore; 831 XShmSegmentInfo info = { 0, }; 832 833 if (!XQueryExtension(dpy, "MIT-SHM", &xshm_opcode, &ignore, &ignore)) 834 return False; 835 836 old_handler = XSetErrorHandler(handle_xerror); 837 XShmDetach(dpy, &info); 838 XSync(dpy, False); 839 (void) XSetErrorHandler(old_handler); 840 841 /* BadRequest means we're a remote client. If we were local we'd 842 * expect BadValue since 'info' has an invalid segment name. 843 */ 844 if (xshm_error == BadRequest) 845 return False; 846 847 xshm_error = 0; 848 return True; 849} 850 851static struct glx_screen * 852driswCreateScreen(int screen, struct glx_display *priv) 853{ 854 __GLXDRIscreen *psp; 855 const __DRIconfig **driver_configs; 856 const __DRIextension **extensions; 857 struct drisw_screen *psc; 858 struct glx_config *configs = NULL, *visuals = NULL; 859 int i; 860 const __DRIextension **loader_extensions_local; 861 862 psc = calloc(1, sizeof *psc); 863 if (psc == NULL) 864 return NULL; 865 866 if (!glx_screen_init(&psc->base, screen, priv)) { 867 free(psc); 868 return NULL; 869 } 870 871 extensions = driOpenDriver(SWRAST_DRIVER_NAME, &psc->driver); 872 if (extensions == NULL) 873 goto handle_error; 874 875 if (!check_xshm(psc->base.dpy)) 876 loader_extensions_local = loader_extensions_noshm; 877 else 878 loader_extensions_local = loader_extensions_shm; 879 880 for (i = 0; extensions[i]; i++) { 881 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 882 psc->core = (__DRIcoreExtension *) extensions[i]; 883 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0) 884 psc->swrast = (__DRIswrastExtension *) extensions[i]; 885 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) 886 psc->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i]; 887 } 888 889 if (psc->core == NULL || psc->swrast == NULL) { 890 ErrorMessageF("core dri extension not found\n"); 891 goto handle_error; 892 } 893 894 if (psc->swrast->base.version >= 4) { 895 psc->driScreen = 896 psc->swrast->createNewScreen2(screen, loader_extensions_local, 897 extensions, 898 &driver_configs, psc); 899 } else { 900 psc->driScreen = 901 psc->swrast->createNewScreen(screen, loader_extensions_local, 902 &driver_configs, psc); 903 } 904 if (psc->driScreen == NULL) { 905 ErrorMessageF("failed to create dri screen\n"); 906 goto handle_error; 907 } 908 909 extensions = psc->core->getExtensions(psc->driScreen); 910 driswBindExtensions(psc, extensions); 911 912 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); 913 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 914 915 if (!configs || !visuals) { 916 ErrorMessageF("No matching fbConfigs or visuals found\n"); 917 goto handle_error; 918 } 919 920 glx_config_destroy_list(psc->base.configs); 921 psc->base.configs = configs; 922 glx_config_destroy_list(psc->base.visuals); 923 psc->base.visuals = visuals; 924 925 psc->driver_configs = driver_configs; 926 927 psc->base.vtable = &drisw_screen_vtable; 928 psp = &psc->vtable; 929 psc->base.driScreen = psp; 930 psp->destroyScreen = driswDestroyScreen; 931 psp->createDrawable = driswCreateDrawable; 932 psp->swapBuffers = driswSwapBuffers; 933 934 if (psc->copySubBuffer) 935 psp->copySubBuffer = driswCopySubBuffer; 936 937 return &psc->base; 938 939 handle_error: 940 if (configs) 941 glx_config_destroy_list(configs); 942 if (visuals) 943 glx_config_destroy_list(visuals); 944 if (psc->driScreen) 945 psc->core->destroyScreen(psc->driScreen); 946 psc->driScreen = NULL; 947 948 if (psc->driver) 949 dlclose(psc->driver); 950 glx_screen_cleanup(&psc->base); 951 free(psc); 952 953 CriticalErrorMessageF("failed to load driver: %s\n", SWRAST_DRIVER_NAME); 954 955 return NULL; 956} 957 958/* Called from __glXFreeDisplayPrivate. 959 */ 960static void 961driswDestroyDisplay(__GLXDRIdisplay * dpy) 962{ 963 free(dpy); 964} 965 966/* 967 * Allocate, initialize and return a __DRIdisplayPrivate object. 968 * This is called from __glXInitialize() when we are given a new 969 * display pointer. 970 */ 971_X_HIDDEN __GLXDRIdisplay * 972driswCreateDisplay(Display * dpy) 973{ 974 struct drisw_display *pdpyp; 975 976 pdpyp = malloc(sizeof *pdpyp); 977 if (pdpyp == NULL) 978 return NULL; 979 980 pdpyp->base.destroyDisplay = driswDestroyDisplay; 981 pdpyp->base.createScreen = driswCreateScreen; 982 983 return &pdpyp->base; 984} 985 986#endif /* GLX_DIRECT_RENDERING */ 987