dri2_glx.c revision d8c443ddde5e9734d60b63b3ec3b5a5ba756d022
1/* 2 * Copyright © 2008 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Soft- 6 * ware"), to deal in the Software without restriction, including without 7 * limitation the rights to use, copy, modify, merge, publish, distribute, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, provided that the above copyright 10 * notice(s) and this permission notice appear in all copies of the Soft- 11 * ware and that both the above copyright notice(s) and this permission 12 * notice appear in supporting documentation. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 22 * MANCE OF THIS SOFTWARE. 23 * 24 * Except as contained in this notice, the name of a copyright holder shall 25 * not be used in advertising or otherwise to promote the sale, use or 26 * other dealings in this Software without prior written authorization of 27 * the copyright holder. 28 * 29 * Authors: 30 * Kristian Høgsberg (krh@redhat.com) 31 */ 32 33#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 34 35#include <X11/Xlib.h> 36#include <X11/extensions/Xfixes.h> 37#include <X11/extensions/Xdamage.h> 38#include "glapi.h" 39#include "glxclient.h" 40#include <X11/extensions/dri2proto.h> 41#include "xf86dri.h" 42#include <dlfcn.h> 43#include <fcntl.h> 44#include <unistd.h> 45#include <sys/types.h> 46#include <sys/mman.h> 47#include "xf86drm.h" 48#include "dri2.h" 49#include "dri_common.h" 50 51/* From xmlpool/options.h, user exposed so should be stable */ 52#define DRI_CONF_VBLANK_NEVER 0 53#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1 54#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2 55#define DRI_CONF_VBLANK_ALWAYS_SYNC 3 56 57#undef DRI2_MINOR 58#define DRI2_MINOR 1 59 60struct dri2_display 61{ 62 __GLXDRIdisplay base; 63 64 /* 65 ** XFree86-DRI version information 66 */ 67 int driMajor; 68 int driMinor; 69 int driPatch; 70 int swapAvailable; 71 int invalidateAvailable; 72 73 __glxHashTable *dri2Hash; 74 75 const __DRIextension *loader_extensions[4]; 76}; 77 78struct dri2_screen { 79 struct glx_screen base; 80 81 __DRIscreen *driScreen; 82 __GLXDRIscreen vtable; 83 const __DRIdri2Extension *dri2; 84 const __DRIcoreExtension *core; 85 86 const __DRI2flushExtension *f; 87 const __DRI2configQueryExtension *config; 88 const __DRItexBufferExtension *texBuffer; 89 const __DRIconfig **driver_configs; 90 91 void *driver; 92 int fd; 93}; 94 95struct dri2_context 96{ 97 struct glx_context base; 98 __DRIcontext *driContext; 99}; 100 101struct dri2_drawable 102{ 103 __GLXDRIdrawable base; 104 __DRIdrawable *driDrawable; 105 __DRIbuffer buffers[5]; 106 int bufferCount; 107 int width, height; 108 int have_back; 109 int have_fake_front; 110 int swap_interval; 111}; 112 113static const struct glx_context_vtable dri2_context_vtable; 114 115static void 116dri2_destroy_context(struct glx_context *context) 117{ 118 struct dri2_context *pcp = (struct dri2_context *) context; 119 struct dri2_screen *psc = (struct dri2_screen *) context->psc; 120 121 driReleaseDrawables(&pcp->base); 122 123 if (context->xid) 124 glx_send_destroy_context(psc->base.dpy, context->xid); 125 126 if (context->extensions) 127 XFree((char *) context->extensions); 128 129 (*psc->core->destroyContext) (pcp->driContext); 130 131 Xfree(pcp); 132} 133 134static Bool 135dri2_bind_context(struct glx_context *context, struct glx_context *old, 136 GLXDrawable draw, GLXDrawable read) 137{ 138 struct dri2_context *pcp = (struct dri2_context *) context; 139 struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; 140 struct dri2_drawable *pdraw, *pread; 141 struct dri2_display *pdp; 142 143 pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw); 144 pread = (struct dri2_drawable *) driFetchDrawable(context, read); 145 146 driReleaseDrawables(&pcp->base); 147 148 if (pdraw == NULL || pread == NULL) 149 return GLXBadDrawable; 150 151 if (!(*psc->core->bindContext) (pcp->driContext, 152 pdraw->driDrawable, pread->driDrawable)) 153 return GLXBadContext; 154 155 /* If the server doesn't send invalidate events, we may miss a 156 * resize before the rendering starts. Invalidate the buffers now 157 * so the driver will recheck before rendering starts. */ 158 pdp = (struct dri2_display *) psc->base.display; 159 if (!pdp->invalidateAvailable) { 160 dri2InvalidateBuffers(psc->base.dpy, pdraw->base.xDrawable); 161 if (pread != pdraw) 162 dri2InvalidateBuffers(psc->base.dpy, pread->base.xDrawable); 163 } 164 165 return Success; 166} 167 168static void 169dri2_unbind_context(struct glx_context *context, struct glx_context *new) 170{ 171 struct dri2_context *pcp = (struct dri2_context *) context; 172 struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; 173 174 (*psc->core->unbindContext) (pcp->driContext); 175} 176 177static struct glx_context * 178dri2_create_context(struct glx_screen *base, 179 struct glx_config *config_base, 180 struct glx_context *shareList, int renderType) 181{ 182 struct dri2_context *pcp, *pcp_shared; 183 struct dri2_screen *psc = (struct dri2_screen *) base; 184 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 185 __DRIcontext *shared = NULL; 186 187 if (shareList) { 188 pcp_shared = (struct dri2_context *) shareList; 189 shared = pcp_shared->driContext; 190 } 191 192 pcp = Xmalloc(sizeof *pcp); 193 if (pcp == NULL) 194 return NULL; 195 196 memset(pcp, 0, sizeof *pcp); 197 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 198 Xfree(pcp); 199 return NULL; 200 } 201 202 pcp->driContext = 203 (*psc->dri2->createNewContext) (psc->driScreen, 204 config->driConfig, shared, pcp); 205 206 if (pcp->driContext == NULL) { 207 Xfree(pcp); 208 return NULL; 209 } 210 211 pcp->base.vtable = &dri2_context_vtable; 212 213 return &pcp->base; 214} 215 216static void 217dri2DestroyDrawable(__GLXDRIdrawable *base) 218{ 219 struct dri2_screen *psc = (struct dri2_screen *) base->psc; 220 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 221 struct glx_display *dpyPriv = psc->base.display; 222 struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display; 223 224 __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable); 225 (*psc->core->destroyDrawable) (pdraw->driDrawable); 226 227 /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable 228 * now, as the application explicitly asked to destroy the GLX 229 * drawable. Otherwise, for legacy drawables, we let the DRI2 230 * drawable linger on the server, since there's no good way of 231 * knowing when the application is done with it. The server will 232 * destroy the DRI2 drawable when it destroys the X drawable or the 233 * client exits anyway. */ 234 if (pdraw->base.xDrawable != pdraw->base.drawable) 235 DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable); 236 237 Xfree(pdraw); 238} 239 240static __GLXDRIdrawable * 241dri2CreateDrawable(struct glx_screen *base, XID xDrawable, 242 GLXDrawable drawable, struct glx_config *config_base) 243{ 244 struct dri2_drawable *pdraw; 245 struct dri2_screen *psc = (struct dri2_screen *) base; 246 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 247 struct glx_display *dpyPriv; 248 struct dri2_display *pdp; 249 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 250 251 pdraw = Xmalloc(sizeof(*pdraw)); 252 if (!pdraw) 253 return NULL; 254 255 memset(pdraw, 0, sizeof *pdraw); 256 pdraw->base.destroyDrawable = dri2DestroyDrawable; 257 pdraw->base.xDrawable = xDrawable; 258 pdraw->base.drawable = drawable; 259 pdraw->base.psc = &psc->base; 260 pdraw->bufferCount = 0; 261 pdraw->swap_interval = 1; /* default may be overridden below */ 262 pdraw->have_back = 0; 263 264 if (psc->config) 265 psc->config->configQueryi(psc->driScreen, 266 "vblank_mode", &vblank_mode); 267 268 switch (vblank_mode) { 269 case DRI_CONF_VBLANK_NEVER: 270 case DRI_CONF_VBLANK_DEF_INTERVAL_0: 271 pdraw->swap_interval = 0; 272 break; 273 case DRI_CONF_VBLANK_DEF_INTERVAL_1: 274 case DRI_CONF_VBLANK_ALWAYS_SYNC: 275 default: 276 pdraw->swap_interval = 1; 277 break; 278 } 279 280 DRI2CreateDrawable(psc->base.dpy, xDrawable); 281 282 dpyPriv = __glXInitialize(psc->base.dpy); 283 pdp = (struct dri2_display *)dpyPriv->dri2Display;; 284 /* Create a new drawable */ 285 pdraw->driDrawable = 286 (*psc->dri2->createNewDrawable) (psc->driScreen, 287 config->driConfig, pdraw); 288 289 if (!pdraw->driDrawable) { 290 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 291 Xfree(pdraw); 292 return NULL; 293 } 294 295 if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) { 296 (*psc->core->destroyDrawable) (pdraw->driDrawable); 297 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 298 Xfree(pdraw); 299 return None; 300 } 301 302 303#ifdef X_DRI2SwapInterval 304 /* 305 * Make sure server has the same swap interval we do for the new 306 * drawable. 307 */ 308 if (pdp->swapAvailable) 309 DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval); 310#endif 311 312 return &pdraw->base; 313} 314 315#ifdef X_DRI2GetMSC 316 317static int 318dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw, 319 int64_t *ust, int64_t *msc, int64_t *sbc) 320{ 321 CARD64 dri2_ust, dri2_msc, dri2_sbc; 322 int ret; 323 324 ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable, 325 &dri2_ust, &dri2_msc, &dri2_sbc); 326 *ust = dri2_ust; 327 *msc = dri2_msc; 328 *sbc = dri2_sbc; 329 330 return ret; 331} 332 333#endif 334 335 336#ifdef X_DRI2WaitMSC 337 338static int 339dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 340 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 341{ 342 CARD64 dri2_ust, dri2_msc, dri2_sbc; 343 int ret; 344 345 ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor, 346 remainder, &dri2_ust, &dri2_msc, &dri2_sbc); 347 *ust = dri2_ust; 348 *msc = dri2_msc; 349 *sbc = dri2_sbc; 350 351 return ret; 352} 353 354static int 355dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 356 int64_t *msc, int64_t *sbc) 357{ 358 CARD64 dri2_ust, dri2_msc, dri2_sbc; 359 int ret; 360 361 ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable, 362 target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc); 363 *ust = dri2_ust; 364 *msc = dri2_msc; 365 *sbc = dri2_sbc; 366 367 return ret; 368} 369 370#endif /* X_DRI2WaitMSC */ 371 372static void 373dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, int width, int height) 374{ 375 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 376 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; 377 XRectangle xrect; 378 XserverRegion region; 379 380 /* Check we have the right attachments */ 381 if (!priv->have_back) 382 return; 383 384 xrect.x = x; 385 xrect.y = priv->height - y - height; 386 xrect.width = width; 387 xrect.height = height; 388 389#ifdef __DRI2_FLUSH 390 if (psc->f) 391 (*psc->f->flush) (priv->driDrawable); 392#endif 393 394 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 395 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 396 DRI2BufferFrontLeft, DRI2BufferBackLeft); 397 398 /* Refresh the fake front (if present) after we just damaged the real 399 * front. 400 */ 401 if (priv->have_fake_front) 402 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 403 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 404 405 XFixesDestroyRegion(psc->base.dpy, region); 406} 407 408static void 409dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src) 410{ 411 XRectangle xrect; 412 XserverRegion region; 413 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 414 415 xrect.x = 0; 416 xrect.y = 0; 417 xrect.width = priv->width; 418 xrect.height = priv->height; 419 420#ifdef __DRI2_FLUSH 421 if (psc->f) 422 (*psc->f->flush) (priv->driDrawable); 423#endif 424 425 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 426 DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src); 427 XFixesDestroyRegion(psc->base.dpy, region); 428 429} 430 431static void 432dri2_wait_x(struct glx_context *gc) 433{ 434 struct dri2_drawable *priv = (struct dri2_drawable *) 435 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 436 437 if (priv == NULL || !priv->have_fake_front) 438 return; 439 440 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 441} 442 443static void 444dri2_wait_gl(struct glx_context *gc) 445{ 446 struct dri2_drawable *priv = (struct dri2_drawable *) 447 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 448 449 if (priv == NULL || !priv->have_fake_front) 450 return; 451 452 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 453} 454 455static void 456dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 457{ 458 struct glx_display *priv; 459 struct dri2_display *pdp; 460 struct glx_context *gc; 461 struct dri2_drawable *pdraw = loaderPrivate; 462 463 if (!pdraw) 464 return; 465 466 if (!pdraw->base.psc) 467 return; 468 469 priv = __glXInitialize(pdraw->base.psc->dpy); 470 pdp = (struct dri2_display *) priv->dri2Display; 471 gc = __glXGetCurrentContext(); 472 473 /* Old servers don't send invalidate events */ 474 if (!pdp->invalidateAvailable) 475 dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable); 476 477 dri2_wait_gl(gc); 478} 479 480 481static void 482dri2DestroyScreen(struct glx_screen *base) 483{ 484 struct dri2_screen *psc = (struct dri2_screen *) base; 485 486 /* Free the direct rendering per screen data */ 487 (*psc->core->destroyScreen) (psc->driScreen); 488 driDestroyConfigs(psc->driver_configs); 489 close(psc->fd); 490 Xfree(psc); 491} 492 493/** 494 * Process list of buffer received from the server 495 * 496 * Processes the list of buffers received in a reply from the server to either 497 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 498 */ 499static void 500process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers, 501 unsigned count) 502{ 503 int i; 504 505 pdraw->bufferCount = count; 506 pdraw->have_fake_front = 0; 507 pdraw->have_back = 0; 508 509 /* This assumes the DRI2 buffer attachment tokens matches the 510 * __DRIbuffer tokens. */ 511 for (i = 0; i < count; i++) { 512 pdraw->buffers[i].attachment = buffers[i].attachment; 513 pdraw->buffers[i].name = buffers[i].name; 514 pdraw->buffers[i].pitch = buffers[i].pitch; 515 pdraw->buffers[i].cpp = buffers[i].cpp; 516 pdraw->buffers[i].flags = buffers[i].flags; 517 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 518 pdraw->have_fake_front = 1; 519 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 520 pdraw->have_back = 1; 521 } 522 523} 524 525unsigned dri2GetSwapEventType(Display* dpy, XID drawable) 526{ 527 struct glx_display *glx_dpy = __glXInitialize(dpy); 528 __GLXDRIdrawable *pdraw; 529 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 530 if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) 531 return 0; 532 return glx_dpy->codes->first_event + GLX_BufferSwapComplete; 533} 534 535static int64_t 536dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 537 int64_t remainder) 538{ 539 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 540 struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy); 541 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 542 struct dri2_display *pdp = 543 (struct dri2_display *)dpyPriv->dri2Display; 544 CARD64 ret = 0; 545 546 /* Check we have the right attachments */ 547 if (!priv->have_back) 548 return ret; 549 550 /* Old servers can't handle swapbuffers */ 551 if (!pdp->swapAvailable) { 552 dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height); 553 } else { 554#ifdef X_DRI2SwapBuffers 555#ifdef __DRI2_FLUSH 556 if (psc->f) { 557 struct glx_context *gc = __glXGetCurrentContext(); 558 559 if (gc) { 560 (*psc->f->flush)(priv->driDrawable); 561 } 562 } 563#endif 564 565 DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, 566 target_msc, divisor, remainder, &ret); 567#endif 568 } 569 570 /* Old servers don't send invalidate events */ 571 if (!pdp->invalidateAvailable) 572 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable); 573 574 return ret; 575} 576 577static __DRIbuffer * 578dri2GetBuffers(__DRIdrawable * driDrawable, 579 int *width, int *height, 580 unsigned int *attachments, int count, 581 int *out_count, void *loaderPrivate) 582{ 583 struct dri2_drawable *pdraw = loaderPrivate; 584 DRI2Buffer *buffers; 585 586 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 587 width, height, attachments, count, out_count); 588 if (buffers == NULL) 589 return NULL; 590 591 pdraw->width = *width; 592 pdraw->height = *height; 593 process_buffers(pdraw, buffers, *out_count); 594 595 Xfree(buffers); 596 597 return pdraw->buffers; 598} 599 600static __DRIbuffer * 601dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 602 int *width, int *height, 603 unsigned int *attachments, int count, 604 int *out_count, void *loaderPrivate) 605{ 606 struct dri2_drawable *pdraw = loaderPrivate; 607 DRI2Buffer *buffers; 608 609 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 610 pdraw->base.xDrawable, 611 width, height, attachments, 612 count, out_count); 613 if (buffers == NULL) 614 return NULL; 615 616 pdraw->width = *width; 617 pdraw->height = *height; 618 process_buffers(pdraw, buffers, *out_count); 619 620 Xfree(buffers); 621 622 return pdraw->buffers; 623} 624 625#ifdef X_DRI2SwapInterval 626 627static int 628dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 629{ 630 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 631 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 632 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 633 634 if (psc->config) 635 psc->config->configQueryi(psc->driScreen, 636 "vblank_mode", &vblank_mode); 637 638 switch (vblank_mode) { 639 case DRI_CONF_VBLANK_NEVER: 640 return GLX_BAD_VALUE; 641 case DRI_CONF_VBLANK_ALWAYS_SYNC: 642 if (interval <= 0) 643 return GLX_BAD_VALUE; 644 break; 645 default: 646 break; 647 } 648 649 DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval); 650 priv->swap_interval = interval; 651 652 return 0; 653} 654 655static int 656dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 657{ 658 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 659 660 return priv->swap_interval; 661} 662 663#endif /* X_DRI2SwapInterval */ 664 665static const __DRIdri2LoaderExtension dri2LoaderExtension = { 666 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 667 dri2GetBuffers, 668 dri2FlushFrontBuffer, 669 dri2GetBuffersWithFormat, 670}; 671 672static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { 673 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 674 dri2GetBuffers, 675 dri2FlushFrontBuffer, 676 NULL, 677}; 678 679#ifdef __DRI_USE_INVALIDATE 680static const __DRIuseInvalidateExtension dri2UseInvalidate = { 681 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 682}; 683#endif 684 685_X_HIDDEN void 686dri2InvalidateBuffers(Display *dpy, XID drawable) 687{ 688 __GLXDRIdrawable *pdraw = 689 dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 690 struct dri2_screen *psc; 691 struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw; 692 693 if (!pdraw) 694 return; 695 696 psc = (struct dri2_screen *) pdraw->psc; 697 698#if __DRI2_FLUSH_VERSION >= 3 699 if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate) 700 psc->f->invalidate(pdp->driDrawable); 701#endif 702} 703 704static void 705dri2_bind_tex_image(Display * dpy, 706 GLXDrawable drawable, 707 int buffer, const int *attrib_list) 708{ 709 struct glx_context *gc = __glXGetCurrentContext(); 710 struct dri2_context *pcp = (struct dri2_context *) gc; 711 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 712 struct glx_display *dpyPriv = __glXInitialize(dpy); 713 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 714 struct dri2_display *pdp = 715 (struct dri2_display *) dpyPriv->dri2Display; 716 struct dri2_screen *psc; 717 718 if (pdraw != NULL) { 719 psc = (struct dri2_screen *) base->psc; 720 721#if __DRI2_FLUSH_VERSION >= 3 722 if (!pdp->invalidateAvailable && psc->f && 723 psc->f->base.version >= 3 && psc->f->invalidate) 724 psc->f->invalidate(pdraw->driDrawable); 725#endif 726 727 if (psc->texBuffer->base.version >= 2 && 728 psc->texBuffer->setTexBuffer2 != NULL) { 729 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 730 pdraw->base.textureTarget, 731 pdraw->base.textureFormat, 732 pdraw->driDrawable); 733 } 734 else { 735 (*psc->texBuffer->setTexBuffer) (pcp->driContext, 736 pdraw->base.textureTarget, 737 pdraw->driDrawable); 738 } 739 } 740} 741 742static void 743dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 744{ 745#if __DRI_TEX_BUFFER_VERSION >= 3 746 struct glx_context *gc = __glXGetCurrentContext(); 747 struct dri2_context *pcp = (struct dri2_context *) gc; 748 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 749 struct glx_display *dpyPriv = __glXInitialize(dpy); 750 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 751 struct dri2_display *pdp = 752 (struct dri2_display *) dpyPriv->dri2Display; 753 struct dri2_screen *psc; 754 755 if (pdraw != NULL) { 756 psc = (struct dri2_screen *) base->psc; 757 758 if (psc->texBuffer->base.version >= 3 && 759 psc->texBuffer->releaseTexBuffer != NULL) { 760 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 761 pdraw->base.textureTarget, 762 pdraw->driDrawable); 763 } 764 } 765#endif 766} 767 768static const struct glx_context_vtable dri2_context_vtable = { 769 dri2_destroy_context, 770 dri2_bind_context, 771 dri2_unbind_context, 772 dri2_wait_gl, 773 dri2_wait_x, 774 DRI_glXUseXFont, 775 dri2_bind_tex_image, 776 dri2_release_tex_image, 777 NULL, /* get_proc_address */ 778}; 779 780static void 781dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions) 782{ 783 int i; 784 785 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 786 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 787 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 788 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 789 790 /* FIXME: if DRI2 version supports it... */ 791 __glXEnableDirectExtension(&psc->base, "INTEL_swap_event"); 792 793 for (i = 0; extensions[i]; i++) { 794 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 795 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 796 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 797 } 798 799 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 800 psc->f = (__DRI2flushExtension *) extensions[i]; 801 /* internal driver extension, no GL extension exposed */ 802 } 803 804 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 805 psc->config = (__DRI2configQueryExtension *) extensions[i]; 806 } 807} 808 809static const struct glx_screen_vtable dri2_screen_vtable = { 810 dri2_create_context 811}; 812 813static struct glx_screen * 814dri2CreateScreen(int screen, struct glx_display * priv) 815{ 816 const __DRIconfig **driver_configs; 817 const __DRIextension **extensions; 818 const struct dri2_display *const pdp = (struct dri2_display *) 819 priv->dri2Display; 820 struct dri2_screen *psc; 821 __GLXDRIscreen *psp; 822 char *driverName, *deviceName; 823 drm_magic_t magic; 824 int i; 825 826 psc = Xmalloc(sizeof *psc); 827 if (psc == NULL) 828 return NULL; 829 830 memset(psc, 0, sizeof *psc); 831 psc->fd = -1; 832 833 if (!glx_screen_init(&psc->base, screen, priv)) { 834 Xfree(psc); 835 return NULL; 836 } 837 838 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen), 839 &driverName, &deviceName)) { 840 glx_screen_cleanup(&psc->base); 841 XFree(psc); 842 InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen); 843 return NULL; 844 } 845 846 psc->driver = driOpenDriver(driverName); 847 if (psc->driver == NULL) { 848 ErrorMessageF("driver pointer missing\n"); 849 goto handle_error; 850 } 851 852 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 853 if (extensions == NULL) { 854 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 855 goto handle_error; 856 } 857 858 for (i = 0; extensions[i]; i++) { 859 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 860 psc->core = (__DRIcoreExtension *) extensions[i]; 861 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 862 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 863 } 864 865 if (psc->core == NULL || psc->dri2 == NULL) { 866 ErrorMessageF("core dri or dri2 extension not found\n"); 867 goto handle_error; 868 } 869 870 psc->fd = open(deviceName, O_RDWR); 871 if (psc->fd < 0) { 872 ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); 873 goto handle_error; 874 } 875 876 if (drmGetMagic(psc->fd, &magic)) { 877 ErrorMessageF("failed to get magic\n"); 878 goto handle_error; 879 } 880 881 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) { 882 ErrorMessageF("failed to authenticate magic %d\n", magic); 883 goto handle_error; 884 } 885 886 887 /* If the server does not support the protocol for 888 * DRI2GetBuffersWithFormat, don't supply that interface to the driver. 889 */ 890 psc->driScreen = 891 psc->dri2->createNewScreen(screen, psc->fd, 892 (const __DRIextension **) 893 &pdp->loader_extensions[0], 894 &driver_configs, psc); 895 896 if (psc->driScreen == NULL) { 897 ErrorMessageF("failed to create dri screen\n"); 898 goto handle_error; 899 } 900 901 extensions = psc->core->getExtensions(psc->driScreen); 902 dri2BindExtensions(psc, extensions); 903 904 psc->base.configs = 905 driConvertConfigs(psc->core, psc->base.configs, driver_configs); 906 psc->base.visuals = 907 driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 908 909 psc->driver_configs = driver_configs; 910 911 psc->base.vtable = &dri2_screen_vtable; 912 psp = &psc->vtable; 913 psc->base.driScreen = psp; 914 psp->destroyScreen = dri2DestroyScreen; 915 psp->createDrawable = dri2CreateDrawable; 916 psp->swapBuffers = dri2SwapBuffers; 917 psp->getDrawableMSC = NULL; 918 psp->waitForMSC = NULL; 919 psp->waitForSBC = NULL; 920 psp->setSwapInterval = NULL; 921 psp->getSwapInterval = NULL; 922 923 if (pdp->driMinor >= 2) { 924#ifdef X_DRI2GetMSC 925 psp->getDrawableMSC = dri2DrawableGetMSC; 926#endif 927#ifdef X_DRI2WaitMSC 928 psp->waitForMSC = dri2WaitForMSC; 929 psp->waitForSBC = dri2WaitForSBC; 930#endif 931#ifdef X_DRI2SwapInterval 932 psp->setSwapInterval = dri2SetSwapInterval; 933 psp->getSwapInterval = dri2GetSwapInterval; 934#endif 935#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval) 936 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 937#endif 938 } 939 940 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always 941 * available.*/ 942 psp->copySubBuffer = dri2CopySubBuffer; 943 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 944 945 Xfree(driverName); 946 Xfree(deviceName); 947 948 return &psc->base; 949 950handle_error: 951 if (psc->fd >= 0) 952 close(psc->fd); 953 if (psc->driver) 954 dlclose(psc->driver); 955 Xfree(driverName); 956 Xfree(deviceName); 957 glx_screen_cleanup(&psc->base); 958 XFree(psc); 959 960 return NULL; 961} 962 963/* Called from __glXFreeDisplayPrivate. 964 */ 965static void 966dri2DestroyDisplay(__GLXDRIdisplay * dpy) 967{ 968 struct dri2_display *pdp = (struct dri2_display *) dpy; 969 970 __glxHashDestroy(pdp->dri2Hash); 971 Xfree(dpy); 972} 973 974_X_HIDDEN __GLXDRIdrawable * 975dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 976{ 977 struct glx_display *d = __glXInitialize(dpy); 978 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display; 979 __GLXDRIdrawable *pdraw; 980 981 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) 982 return pdraw; 983 984 return NULL; 985} 986 987/* 988 * Allocate, initialize and return a __DRIdisplayPrivate object. 989 * This is called from __glXInitialize() when we are given a new 990 * display pointer. 991 */ 992_X_HIDDEN __GLXDRIdisplay * 993dri2CreateDisplay(Display * dpy) 994{ 995 struct dri2_display *pdp; 996 int eventBase, errorBase, i; 997 998 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 999 return NULL; 1000 1001 pdp = Xmalloc(sizeof *pdp); 1002 if (pdp == NULL) 1003 return NULL; 1004 1005 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { 1006 Xfree(pdp); 1007 return NULL; 1008 } 1009 1010 pdp->driPatch = 0; 1011 pdp->swapAvailable = (pdp->driMinor >= 2); 1012 pdp->invalidateAvailable = (pdp->driMinor >= 3); 1013 1014 pdp->base.destroyDisplay = dri2DestroyDisplay; 1015 pdp->base.createScreen = dri2CreateScreen; 1016 1017 i = 0; 1018 if (pdp->driMinor < 1) 1019 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base; 1020 else 1021 pdp->loader_extensions[i++] = &dri2LoaderExtension.base; 1022 1023 pdp->loader_extensions[i++] = &systemTimeExtension.base; 1024 1025#ifdef __DRI_USE_INVALIDATE 1026 pdp->loader_extensions[i++] = &dri2UseInvalidate.base; 1027#endif 1028 pdp->loader_extensions[i++] = NULL; 1029 1030 pdp->dri2Hash = __glxHashCreate(); 1031 if (pdp->dri2Hash == NULL) { 1032 Xfree(pdp); 1033 return NULL; 1034 } 1035 1036 return &pdp->base; 1037} 1038 1039#endif /* GLX_DIRECT_RENDERING */ 1040