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