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