dri2_glx.c revision 63a6fd6603574c1c01324fbeb0863e39d3864c16
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 "glapi.h" 38#include "glxclient.h" 39#include <X11/extensions/dri2proto.h> 40#include "xf86dri.h" 41#include <dlfcn.h> 42#include <fcntl.h> 43#include <unistd.h> 44#include <sys/types.h> 45#include <sys/mman.h> 46#include "xf86drm.h" 47#include "dri2.h" 48#include "dri_common.h" 49 50/* From xmlpool/options.h, user exposed so should be stable */ 51#define DRI_CONF_VBLANK_NEVER 0 52#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1 53#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2 54#define DRI_CONF_VBLANK_ALWAYS_SYNC 3 55 56#undef DRI2_MINOR 57#define DRI2_MINOR 1 58 59struct dri2_display 60{ 61 __GLXDRIdisplay base; 62 63 /* 64 ** XFree86-DRI version information 65 */ 66 int driMajor; 67 int driMinor; 68 int driPatch; 69 int swapAvailable; 70 int invalidateAvailable; 71 72 __glxHashTable *dri2Hash; 73 74 const __DRIextension *loader_extensions[4]; 75}; 76 77struct dri2_screen { 78 struct glx_screen base; 79 80 __DRIscreen *driScreen; 81 __GLXDRIscreen vtable; 82 const __DRIdri2Extension *dri2; 83 const __DRIcoreExtension *core; 84 85 const __DRI2flushExtension *f; 86 const __DRI2configQueryExtension *config; 87 const __DRItexBufferExtension *texBuffer; 88 const __DRI2throttleExtension *throttle; 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 372/** 373 * dri2Throttle - Request driver throttling 374 * 375 * This function uses the DRI2 throttle extension to give the 376 * driver the opportunity to throttle on flush front, copysubbuffer 377 * and swapbuffers. 378 */ 379static void 380dri2Throttle(struct dri2_screen *psc, 381 struct dri2_drawable *draw, 382 enum __DRI2throttleReason reason) 383{ 384 if (psc->throttle) { 385 struct glx_context *gc = __glXGetCurrentContext(); 386 struct dri2_context *dri2Ctx = (struct dri2_context *)gc; 387 __DRIcontext *ctx = 388 (dri2Ctx) ? dri2Ctx->driContext : NULL; 389 390 psc->throttle->throttle(ctx, draw->driDrawable, reason); 391 } 392} 393 394static void 395__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, 396 int width, int height, 397 enum __DRI2throttleReason reason) 398{ 399 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 400 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; 401 XRectangle xrect; 402 XserverRegion region; 403 404 /* Check we have the right attachments */ 405 if (!priv->have_back) 406 return; 407 408 xrect.x = x; 409 xrect.y = priv->height - y - height; 410 xrect.width = width; 411 xrect.height = height; 412 413#ifdef __DRI2_FLUSH 414 if (psc->f) 415 (*psc->f->flush) (priv->driDrawable); 416#endif 417 418 dri2Throttle(psc, priv, reason); 419 420 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 421 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 422 DRI2BufferFrontLeft, DRI2BufferBackLeft); 423 424 /* Refresh the fake front (if present) after we just damaged the real 425 * front. 426 */ 427 if (priv->have_fake_front) 428 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 429 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 430 431 XFixesDestroyRegion(psc->base.dpy, region); 432} 433 434static void 435dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, 436 int width, int height) 437{ 438 __dri2CopySubBuffer(pdraw, x, y, width, height, 439 __DRI2_THROTTLE_COPYSUBBUFFER); 440} 441 442 443static void 444dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src) 445{ 446 XRectangle xrect; 447 XserverRegion region; 448 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 449 450 xrect.x = 0; 451 xrect.y = 0; 452 xrect.width = priv->width; 453 xrect.height = priv->height; 454 455#ifdef __DRI2_FLUSH 456 if (psc->f) 457 (*psc->f->flush) (priv->driDrawable); 458#endif 459 460 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 461 DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src); 462 XFixesDestroyRegion(psc->base.dpy, region); 463 464} 465 466static void 467dri2_wait_x(struct glx_context *gc) 468{ 469 struct dri2_drawable *priv = (struct dri2_drawable *) 470 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 471 472 if (priv == NULL || !priv->have_fake_front) 473 return; 474 475 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 476} 477 478static void 479dri2_wait_gl(struct glx_context *gc) 480{ 481 struct dri2_drawable *priv = (struct dri2_drawable *) 482 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 483 484 if (priv == NULL || !priv->have_fake_front) 485 return; 486 487 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 488} 489 490static void 491dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 492{ 493 struct glx_display *priv; 494 struct dri2_display *pdp; 495 struct glx_context *gc; 496 struct dri2_drawable *pdraw = loaderPrivate; 497 struct dri2_screen *psc; 498 499 if (!pdraw) 500 return; 501 502 if (!pdraw->base.psc) 503 return; 504 505 psc = (struct dri2_screen *) pdraw->base.psc; 506 507 priv = __glXInitialize(psc->base.dpy); 508 pdp = (struct dri2_display *) priv->dri2Display; 509 gc = __glXGetCurrentContext(); 510 511 dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT); 512 513 /* Old servers don't send invalidate events */ 514 if (!pdp->invalidateAvailable) 515 dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable); 516 517 dri2_wait_gl(gc); 518} 519 520 521static void 522dri2DestroyScreen(struct glx_screen *base) 523{ 524 struct dri2_screen *psc = (struct dri2_screen *) base; 525 526 /* Free the direct rendering per screen data */ 527 (*psc->core->destroyScreen) (psc->driScreen); 528 driDestroyConfigs(psc->driver_configs); 529 close(psc->fd); 530 Xfree(psc); 531} 532 533/** 534 * Process list of buffer received from the server 535 * 536 * Processes the list of buffers received in a reply from the server to either 537 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 538 */ 539static void 540process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers, 541 unsigned count) 542{ 543 int i; 544 545 pdraw->bufferCount = count; 546 pdraw->have_fake_front = 0; 547 pdraw->have_back = 0; 548 549 /* This assumes the DRI2 buffer attachment tokens matches the 550 * __DRIbuffer tokens. */ 551 for (i = 0; i < count; i++) { 552 pdraw->buffers[i].attachment = buffers[i].attachment; 553 pdraw->buffers[i].name = buffers[i].name; 554 pdraw->buffers[i].pitch = buffers[i].pitch; 555 pdraw->buffers[i].cpp = buffers[i].cpp; 556 pdraw->buffers[i].flags = buffers[i].flags; 557 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 558 pdraw->have_fake_front = 1; 559 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 560 pdraw->have_back = 1; 561 } 562 563} 564 565unsigned dri2GetSwapEventType(Display* dpy, XID drawable) 566{ 567 struct glx_display *glx_dpy = __glXInitialize(dpy); 568 __GLXDRIdrawable *pdraw; 569 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 570 if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) 571 return 0; 572 return glx_dpy->codes->first_event + GLX_BufferSwapComplete; 573} 574 575static int64_t 576dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 577 int64_t remainder) 578{ 579 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 580 struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy); 581 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 582 struct dri2_display *pdp = 583 (struct dri2_display *)dpyPriv->dri2Display; 584 CARD64 ret = 0; 585 586 /* Check we have the right attachments */ 587 if (!priv->have_back) 588 return ret; 589 590 /* Old servers can't handle swapbuffers */ 591 if (!pdp->swapAvailable) { 592 __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height, 593 __DRI2_THROTTLE_SWAPBUFFER); 594 } else { 595#ifdef X_DRI2SwapBuffers 596#ifdef __DRI2_FLUSH 597 if (psc->f) { 598 struct glx_context *gc = __glXGetCurrentContext(); 599 600 if (gc) { 601 (*psc->f->flush)(priv->driDrawable); 602 } 603 } 604#endif 605 606 dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER); 607 608 DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, 609 target_msc, divisor, remainder, &ret); 610#endif 611 } 612 613 /* Old servers don't send invalidate events */ 614 if (!pdp->invalidateAvailable) 615 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable); 616 617 return ret; 618} 619 620static __DRIbuffer * 621dri2GetBuffers(__DRIdrawable * driDrawable, 622 int *width, int *height, 623 unsigned int *attachments, int count, 624 int *out_count, void *loaderPrivate) 625{ 626 struct dri2_drawable *pdraw = loaderPrivate; 627 DRI2Buffer *buffers; 628 629 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 630 width, height, attachments, count, out_count); 631 if (buffers == NULL) 632 return NULL; 633 634 pdraw->width = *width; 635 pdraw->height = *height; 636 process_buffers(pdraw, buffers, *out_count); 637 638 Xfree(buffers); 639 640 return pdraw->buffers; 641} 642 643static __DRIbuffer * 644dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 645 int *width, int *height, 646 unsigned int *attachments, int count, 647 int *out_count, void *loaderPrivate) 648{ 649 struct dri2_drawable *pdraw = loaderPrivate; 650 DRI2Buffer *buffers; 651 652 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 653 pdraw->base.xDrawable, 654 width, height, attachments, 655 count, out_count); 656 if (buffers == NULL) 657 return NULL; 658 659 pdraw->width = *width; 660 pdraw->height = *height; 661 process_buffers(pdraw, buffers, *out_count); 662 663 Xfree(buffers); 664 665 return pdraw->buffers; 666} 667 668#ifdef X_DRI2SwapInterval 669 670static int 671dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 672{ 673 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 674 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 675 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 676 677 if (psc->config) 678 psc->config->configQueryi(psc->driScreen, 679 "vblank_mode", &vblank_mode); 680 681 switch (vblank_mode) { 682 case DRI_CONF_VBLANK_NEVER: 683 return GLX_BAD_VALUE; 684 case DRI_CONF_VBLANK_ALWAYS_SYNC: 685 if (interval <= 0) 686 return GLX_BAD_VALUE; 687 break; 688 default: 689 break; 690 } 691 692 DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval); 693 priv->swap_interval = interval; 694 695 return 0; 696} 697 698static int 699dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 700{ 701 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 702 703 return priv->swap_interval; 704} 705 706#endif /* X_DRI2SwapInterval */ 707 708static const __DRIdri2LoaderExtension dri2LoaderExtension = { 709 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 710 dri2GetBuffers, 711 dri2FlushFrontBuffer, 712 dri2GetBuffersWithFormat, 713}; 714 715static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { 716 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 717 dri2GetBuffers, 718 dri2FlushFrontBuffer, 719 NULL, 720}; 721 722#ifdef __DRI_USE_INVALIDATE 723static const __DRIuseInvalidateExtension dri2UseInvalidate = { 724 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 725}; 726#endif 727 728_X_HIDDEN void 729dri2InvalidateBuffers(Display *dpy, XID drawable) 730{ 731 __GLXDRIdrawable *pdraw = 732 dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 733 struct dri2_screen *psc; 734 struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw; 735 736 if (!pdraw) 737 return; 738 739 psc = (struct dri2_screen *) pdraw->psc; 740 741#if __DRI2_FLUSH_VERSION >= 3 742 if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate) 743 psc->f->invalidate(pdp->driDrawable); 744#endif 745} 746 747static void 748dri2_bind_tex_image(Display * dpy, 749 GLXDrawable drawable, 750 int buffer, const int *attrib_list) 751{ 752 struct glx_context *gc = __glXGetCurrentContext(); 753 struct dri2_context *pcp = (struct dri2_context *) gc; 754 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 755 struct glx_display *dpyPriv = __glXInitialize(dpy); 756 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 757 struct dri2_display *pdp = 758 (struct dri2_display *) dpyPriv->dri2Display; 759 struct dri2_screen *psc; 760 761 if (pdraw != NULL) { 762 psc = (struct dri2_screen *) base->psc; 763 764#if __DRI2_FLUSH_VERSION >= 3 765 if (!pdp->invalidateAvailable && psc->f && 766 psc->f->base.version >= 3 && psc->f->invalidate) 767 psc->f->invalidate(pdraw->driDrawable); 768#endif 769 770 if (psc->texBuffer->base.version >= 2 && 771 psc->texBuffer->setTexBuffer2 != NULL) { 772 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 773 pdraw->base.textureTarget, 774 pdraw->base.textureFormat, 775 pdraw->driDrawable); 776 } 777 else { 778 (*psc->texBuffer->setTexBuffer) (pcp->driContext, 779 pdraw->base.textureTarget, 780 pdraw->driDrawable); 781 } 782 } 783} 784 785static void 786dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 787{ 788#if __DRI_TEX_BUFFER_VERSION >= 3 789 struct glx_context *gc = __glXGetCurrentContext(); 790 struct dri2_context *pcp = (struct dri2_context *) gc; 791 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 792 struct glx_display *dpyPriv = __glXInitialize(dpy); 793 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 794 struct dri2_display *pdp = 795 (struct dri2_display *) dpyPriv->dri2Display; 796 struct dri2_screen *psc; 797 798 if (pdraw != NULL) { 799 psc = (struct dri2_screen *) base->psc; 800 801 if (psc->texBuffer->base.version >= 3 && 802 psc->texBuffer->releaseTexBuffer != NULL) { 803 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 804 pdraw->base.textureTarget, 805 pdraw->driDrawable); 806 } 807 } 808#endif 809} 810 811static const struct glx_context_vtable dri2_context_vtable = { 812 dri2_destroy_context, 813 dri2_bind_context, 814 dri2_unbind_context, 815 dri2_wait_gl, 816 dri2_wait_x, 817 DRI_glXUseXFont, 818 dri2_bind_tex_image, 819 dri2_release_tex_image, 820 NULL, /* get_proc_address */ 821}; 822 823static void 824dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions) 825{ 826 int i; 827 828 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 829 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 830 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 831 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 832 833 /* FIXME: if DRI2 version supports it... */ 834 __glXEnableDirectExtension(&psc->base, "INTEL_swap_event"); 835 836 for (i = 0; extensions[i]; i++) { 837 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 838 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 839 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 840 } 841 842 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 843 psc->f = (__DRI2flushExtension *) extensions[i]; 844 /* internal driver extension, no GL extension exposed */ 845 } 846 847 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 848 psc->config = (__DRI2configQueryExtension *) extensions[i]; 849 850 if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0))) 851 psc->throttle = (__DRI2throttleExtension *) extensions[i]; 852 } 853} 854 855static const struct glx_screen_vtable dri2_screen_vtable = { 856 dri2_create_context 857}; 858 859static struct glx_screen * 860dri2CreateScreen(int screen, struct glx_display * priv) 861{ 862 const __DRIconfig **driver_configs; 863 const __DRIextension **extensions; 864 const struct dri2_display *const pdp = (struct dri2_display *) 865 priv->dri2Display; 866 struct dri2_screen *psc; 867 __GLXDRIscreen *psp; 868 struct glx_config *configs = NULL, *visuals = NULL; 869 char *driverName, *deviceName; 870 drm_magic_t magic; 871 int i; 872 873 psc = Xmalloc(sizeof *psc); 874 if (psc == NULL) 875 return NULL; 876 877 memset(psc, 0, sizeof *psc); 878 psc->fd = -1; 879 880 if (!glx_screen_init(&psc->base, screen, priv)) { 881 Xfree(psc); 882 return NULL; 883 } 884 885 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen), 886 &driverName, &deviceName)) { 887 glx_screen_cleanup(&psc->base); 888 XFree(psc); 889 InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen); 890 return NULL; 891 } 892 893 psc->driver = driOpenDriver(driverName); 894 if (psc->driver == NULL) { 895 ErrorMessageF("driver pointer missing\n"); 896 goto handle_error; 897 } 898 899 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 900 if (extensions == NULL) { 901 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 902 goto handle_error; 903 } 904 905 for (i = 0; extensions[i]; i++) { 906 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 907 psc->core = (__DRIcoreExtension *) extensions[i]; 908 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 909 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 910 } 911 912 if (psc->core == NULL || psc->dri2 == NULL) { 913 ErrorMessageF("core dri or dri2 extension not found\n"); 914 goto handle_error; 915 } 916 917 psc->fd = open(deviceName, O_RDWR); 918 if (psc->fd < 0) { 919 ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); 920 goto handle_error; 921 } 922 923 if (drmGetMagic(psc->fd, &magic)) { 924 ErrorMessageF("failed to get magic\n"); 925 goto handle_error; 926 } 927 928 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) { 929 ErrorMessageF("failed to authenticate magic %d\n", magic); 930 goto handle_error; 931 } 932 933 934 /* If the server does not support the protocol for 935 * DRI2GetBuffersWithFormat, don't supply that interface to the driver. 936 */ 937 psc->driScreen = 938 psc->dri2->createNewScreen(screen, psc->fd, 939 (const __DRIextension **) 940 &pdp->loader_extensions[0], 941 &driver_configs, psc); 942 943 if (psc->driScreen == NULL) { 944 ErrorMessageF("failed to create dri screen\n"); 945 goto handle_error; 946 } 947 948 extensions = psc->core->getExtensions(psc->driScreen); 949 dri2BindExtensions(psc, extensions); 950 951 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); 952 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 953 954 if (!configs || !visuals) 955 goto handle_error; 956 957 glx_config_destroy_list(psc->base.configs); 958 psc->base.configs = configs; 959 glx_config_destroy_list(psc->base.visuals); 960 psc->base.visuals = visuals; 961 962 psc->driver_configs = driver_configs; 963 964 psc->base.vtable = &dri2_screen_vtable; 965 psp = &psc->vtable; 966 psc->base.driScreen = psp; 967 psp->destroyScreen = dri2DestroyScreen; 968 psp->createDrawable = dri2CreateDrawable; 969 psp->swapBuffers = dri2SwapBuffers; 970 psp->getDrawableMSC = NULL; 971 psp->waitForMSC = NULL; 972 psp->waitForSBC = NULL; 973 psp->setSwapInterval = NULL; 974 psp->getSwapInterval = NULL; 975 976 if (pdp->driMinor >= 2) { 977#ifdef X_DRI2GetMSC 978 psp->getDrawableMSC = dri2DrawableGetMSC; 979#endif 980#ifdef X_DRI2WaitMSC 981 psp->waitForMSC = dri2WaitForMSC; 982 psp->waitForSBC = dri2WaitForSBC; 983#endif 984#ifdef X_DRI2SwapInterval 985 psp->setSwapInterval = dri2SetSwapInterval; 986 psp->getSwapInterval = dri2GetSwapInterval; 987#endif 988#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval) 989 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 990#endif 991 } 992 993 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always 994 * available.*/ 995 psp->copySubBuffer = dri2CopySubBuffer; 996 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 997 998 Xfree(driverName); 999 Xfree(deviceName); 1000 1001 return &psc->base; 1002 1003handle_error: 1004 if (configs) 1005 glx_config_destroy_list(configs); 1006 if (visuals) 1007 glx_config_destroy_list(visuals); 1008 if (psc->driScreen) 1009 psc->core->destroyScreen(psc->driScreen); 1010 psc->driScreen = NULL; 1011 if (psc->fd >= 0) 1012 close(psc->fd); 1013 if (psc->driver) 1014 dlclose(psc->driver); 1015 1016 Xfree(driverName); 1017 Xfree(deviceName); 1018 glx_screen_cleanup(&psc->base); 1019 XFree(psc); 1020 1021 return NULL; 1022} 1023 1024/* Called from __glXFreeDisplayPrivate. 1025 */ 1026static void 1027dri2DestroyDisplay(__GLXDRIdisplay * dpy) 1028{ 1029 struct dri2_display *pdp = (struct dri2_display *) dpy; 1030 1031 __glxHashDestroy(pdp->dri2Hash); 1032 Xfree(dpy); 1033} 1034 1035_X_HIDDEN __GLXDRIdrawable * 1036dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 1037{ 1038 struct glx_display *d = __glXInitialize(dpy); 1039 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display; 1040 __GLXDRIdrawable *pdraw; 1041 1042 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) 1043 return pdraw; 1044 1045 return NULL; 1046} 1047 1048/* 1049 * Allocate, initialize and return a __DRIdisplayPrivate object. 1050 * This is called from __glXInitialize() when we are given a new 1051 * display pointer. 1052 */ 1053_X_HIDDEN __GLXDRIdisplay * 1054dri2CreateDisplay(Display * dpy) 1055{ 1056 struct dri2_display *pdp; 1057 int eventBase, errorBase, i; 1058 1059 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 1060 return NULL; 1061 1062 pdp = Xmalloc(sizeof *pdp); 1063 if (pdp == NULL) 1064 return NULL; 1065 1066 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { 1067 Xfree(pdp); 1068 return NULL; 1069 } 1070 1071 pdp->driPatch = 0; 1072 pdp->swapAvailable = (pdp->driMinor >= 2); 1073 pdp->invalidateAvailable = (pdp->driMinor >= 3); 1074 1075 pdp->base.destroyDisplay = dri2DestroyDisplay; 1076 pdp->base.createScreen = dri2CreateScreen; 1077 1078 i = 0; 1079 if (pdp->driMinor < 1) 1080 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base; 1081 else 1082 pdp->loader_extensions[i++] = &dri2LoaderExtension.base; 1083 1084 pdp->loader_extensions[i++] = &systemTimeExtension.base; 1085 1086#ifdef __DRI_USE_INVALIDATE 1087 pdp->loader_extensions[i++] = &dri2UseInvalidate.base; 1088#endif 1089 pdp->loader_extensions[i++] = NULL; 1090 1091 pdp->dri2Hash = __glxHashCreate(); 1092 if (pdp->dri2Hash == NULL) { 1093 Xfree(pdp); 1094 return NULL; 1095 } 1096 1097 return &pdp->base; 1098} 1099 1100#endif /* GLX_DIRECT_RENDERING */ 1101