dri2_glx.c revision c4a8c54c3bb31547cba57702ffea99293afef522
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 /* If the shareList context is not a DRI2 context, we cannot possibly 189 * create a DRI2 context that shares it. 190 */ 191 if (shareList->vtable->destroy != dri2_destroy_context) { 192 return NULL; 193 } 194 195 pcp_shared = (struct dri2_context *) shareList; 196 shared = pcp_shared->driContext; 197 } 198 199 pcp = Xmalloc(sizeof *pcp); 200 if (pcp == NULL) 201 return NULL; 202 203 memset(pcp, 0, sizeof *pcp); 204 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 205 Xfree(pcp); 206 return NULL; 207 } 208 209 pcp->driContext = 210 (*psc->dri2->createNewContext) (psc->driScreen, 211 config->driConfig, shared, pcp); 212 213 if (pcp->driContext == NULL) { 214 Xfree(pcp); 215 return NULL; 216 } 217 218 pcp->base.vtable = &dri2_context_vtable; 219 220 return &pcp->base; 221} 222 223static void 224dri2DestroyDrawable(__GLXDRIdrawable *base) 225{ 226 struct dri2_screen *psc = (struct dri2_screen *) base->psc; 227 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 228 struct glx_display *dpyPriv = psc->base.display; 229 struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display; 230 231 __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable); 232 (*psc->core->destroyDrawable) (pdraw->driDrawable); 233 234 /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable 235 * now, as the application explicitly asked to destroy the GLX 236 * drawable. Otherwise, for legacy drawables, we let the DRI2 237 * drawable linger on the server, since there's no good way of 238 * knowing when the application is done with it. The server will 239 * destroy the DRI2 drawable when it destroys the X drawable or the 240 * client exits anyway. */ 241 if (pdraw->base.xDrawable != pdraw->base.drawable) 242 DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable); 243 244 Xfree(pdraw); 245} 246 247static __GLXDRIdrawable * 248dri2CreateDrawable(struct glx_screen *base, XID xDrawable, 249 GLXDrawable drawable, struct glx_config *config_base) 250{ 251 struct dri2_drawable *pdraw; 252 struct dri2_screen *psc = (struct dri2_screen *) base; 253 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 254 struct glx_display *dpyPriv; 255 struct dri2_display *pdp; 256 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 257 258 pdraw = Xmalloc(sizeof(*pdraw)); 259 if (!pdraw) 260 return NULL; 261 262 memset(pdraw, 0, sizeof *pdraw); 263 pdraw->base.destroyDrawable = dri2DestroyDrawable; 264 pdraw->base.xDrawable = xDrawable; 265 pdraw->base.drawable = drawable; 266 pdraw->base.psc = &psc->base; 267 pdraw->bufferCount = 0; 268 pdraw->swap_interval = 1; /* default may be overridden below */ 269 pdraw->have_back = 0; 270 271 if (psc->config) 272 psc->config->configQueryi(psc->driScreen, 273 "vblank_mode", &vblank_mode); 274 275 switch (vblank_mode) { 276 case DRI_CONF_VBLANK_NEVER: 277 case DRI_CONF_VBLANK_DEF_INTERVAL_0: 278 pdraw->swap_interval = 0; 279 break; 280 case DRI_CONF_VBLANK_DEF_INTERVAL_1: 281 case DRI_CONF_VBLANK_ALWAYS_SYNC: 282 default: 283 pdraw->swap_interval = 1; 284 break; 285 } 286 287 DRI2CreateDrawable(psc->base.dpy, xDrawable); 288 289 dpyPriv = __glXInitialize(psc->base.dpy); 290 pdp = (struct dri2_display *)dpyPriv->dri2Display;; 291 /* Create a new drawable */ 292 pdraw->driDrawable = 293 (*psc->dri2->createNewDrawable) (psc->driScreen, 294 config->driConfig, pdraw); 295 296 if (!pdraw->driDrawable) { 297 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 298 Xfree(pdraw); 299 return NULL; 300 } 301 302 if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) { 303 (*psc->core->destroyDrawable) (pdraw->driDrawable); 304 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 305 Xfree(pdraw); 306 return None; 307 } 308 309 310#ifdef X_DRI2SwapInterval 311 /* 312 * Make sure server has the same swap interval we do for the new 313 * drawable. 314 */ 315 if (pdp->swapAvailable) 316 DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval); 317#endif 318 319 return &pdraw->base; 320} 321 322#ifdef X_DRI2GetMSC 323 324static int 325dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw, 326 int64_t *ust, int64_t *msc, int64_t *sbc) 327{ 328 CARD64 dri2_ust, dri2_msc, dri2_sbc; 329 int ret; 330 331 ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable, 332 &dri2_ust, &dri2_msc, &dri2_sbc); 333 *ust = dri2_ust; 334 *msc = dri2_msc; 335 *sbc = dri2_sbc; 336 337 return ret; 338} 339 340#endif 341 342 343#ifdef X_DRI2WaitMSC 344 345static int 346dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 347 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 348{ 349 CARD64 dri2_ust, dri2_msc, dri2_sbc; 350 int ret; 351 352 ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor, 353 remainder, &dri2_ust, &dri2_msc, &dri2_sbc); 354 *ust = dri2_ust; 355 *msc = dri2_msc; 356 *sbc = dri2_sbc; 357 358 return ret; 359} 360 361static int 362dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 363 int64_t *msc, int64_t *sbc) 364{ 365 CARD64 dri2_ust, dri2_msc, dri2_sbc; 366 int ret; 367 368 ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable, 369 target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc); 370 *ust = dri2_ust; 371 *msc = dri2_msc; 372 *sbc = dri2_sbc; 373 374 return ret; 375} 376 377#endif /* X_DRI2WaitMSC */ 378 379/** 380 * dri2Throttle - Request driver throttling 381 * 382 * This function uses the DRI2 throttle extension to give the 383 * driver the opportunity to throttle on flush front, copysubbuffer 384 * and swapbuffers. 385 */ 386static void 387dri2Throttle(struct dri2_screen *psc, 388 struct dri2_drawable *draw, 389 enum __DRI2throttleReason reason) 390{ 391 if (psc->throttle) { 392 struct glx_context *gc = __glXGetCurrentContext(); 393 struct dri2_context *dri2Ctx = (struct dri2_context *)gc; 394 __DRIcontext *ctx = 395 (dri2Ctx) ? dri2Ctx->driContext : NULL; 396 397 psc->throttle->throttle(ctx, draw->driDrawable, reason); 398 } 399} 400 401static void 402__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, 403 int width, int height, 404 enum __DRI2throttleReason reason) 405{ 406 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 407 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; 408 XRectangle xrect; 409 XserverRegion region; 410 411 /* Check we have the right attachments */ 412 if (!priv->have_back) 413 return; 414 415 xrect.x = x; 416 xrect.y = priv->height - y - height; 417 xrect.width = width; 418 xrect.height = height; 419 420#ifdef __DRI2_FLUSH 421 if (psc->f) 422 (*psc->f->flush) (priv->driDrawable); 423#endif 424 425 dri2Throttle(psc, priv, reason); 426 427 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 428 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 429 DRI2BufferFrontLeft, DRI2BufferBackLeft); 430 431 /* Refresh the fake front (if present) after we just damaged the real 432 * front. 433 */ 434 if (priv->have_fake_front) 435 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 436 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 437 438 XFixesDestroyRegion(psc->base.dpy, region); 439} 440 441static void 442dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, 443 int width, int height) 444{ 445 __dri2CopySubBuffer(pdraw, x, y, width, height, 446 __DRI2_THROTTLE_COPYSUBBUFFER); 447} 448 449 450static void 451dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src) 452{ 453 XRectangle xrect; 454 XserverRegion region; 455 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 456 457 xrect.x = 0; 458 xrect.y = 0; 459 xrect.width = priv->width; 460 xrect.height = priv->height; 461 462#ifdef __DRI2_FLUSH 463 if (psc->f) 464 (*psc->f->flush) (priv->driDrawable); 465#endif 466 467 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 468 DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src); 469 XFixesDestroyRegion(psc->base.dpy, region); 470 471} 472 473static void 474dri2_wait_x(struct glx_context *gc) 475{ 476 struct dri2_drawable *priv = (struct dri2_drawable *) 477 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 478 479 if (priv == NULL || !priv->have_fake_front) 480 return; 481 482 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 483} 484 485static void 486dri2_wait_gl(struct glx_context *gc) 487{ 488 struct dri2_drawable *priv = (struct dri2_drawable *) 489 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 490 491 if (priv == NULL || !priv->have_fake_front) 492 return; 493 494 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 495} 496 497static void 498dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 499{ 500 struct glx_display *priv; 501 struct dri2_display *pdp; 502 struct glx_context *gc; 503 struct dri2_drawable *pdraw = loaderPrivate; 504 struct dri2_screen *psc; 505 506 if (!pdraw) 507 return; 508 509 if (!pdraw->base.psc) 510 return; 511 512 psc = (struct dri2_screen *) pdraw->base.psc; 513 514 priv = __glXInitialize(psc->base.dpy); 515 pdp = (struct dri2_display *) priv->dri2Display; 516 gc = __glXGetCurrentContext(); 517 518 dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT); 519 520 /* Old servers don't send invalidate events */ 521 if (!pdp->invalidateAvailable) 522 dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable); 523 524 dri2_wait_gl(gc); 525} 526 527 528static void 529dri2DestroyScreen(struct glx_screen *base) 530{ 531 struct dri2_screen *psc = (struct dri2_screen *) base; 532 533 /* Free the direct rendering per screen data */ 534 (*psc->core->destroyScreen) (psc->driScreen); 535 driDestroyConfigs(psc->driver_configs); 536 close(psc->fd); 537 Xfree(psc); 538} 539 540/** 541 * Process list of buffer received from the server 542 * 543 * Processes the list of buffers received in a reply from the server to either 544 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 545 */ 546static void 547process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers, 548 unsigned count) 549{ 550 int i; 551 552 pdraw->bufferCount = count; 553 pdraw->have_fake_front = 0; 554 pdraw->have_back = 0; 555 556 /* This assumes the DRI2 buffer attachment tokens matches the 557 * __DRIbuffer tokens. */ 558 for (i = 0; i < count; i++) { 559 pdraw->buffers[i].attachment = buffers[i].attachment; 560 pdraw->buffers[i].name = buffers[i].name; 561 pdraw->buffers[i].pitch = buffers[i].pitch; 562 pdraw->buffers[i].cpp = buffers[i].cpp; 563 pdraw->buffers[i].flags = buffers[i].flags; 564 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 565 pdraw->have_fake_front = 1; 566 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 567 pdraw->have_back = 1; 568 } 569 570} 571 572unsigned dri2GetSwapEventType(Display* dpy, XID drawable) 573{ 574 struct glx_display *glx_dpy = __glXInitialize(dpy); 575 __GLXDRIdrawable *pdraw; 576 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 577 if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) 578 return 0; 579 return glx_dpy->codes->first_event + GLX_BufferSwapComplete; 580} 581 582static int64_t 583dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 584 int64_t remainder) 585{ 586 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 587 struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy); 588 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 589 struct dri2_display *pdp = 590 (struct dri2_display *)dpyPriv->dri2Display; 591 CARD64 ret = 0; 592 593 /* Check we have the right attachments */ 594 if (!priv->have_back) 595 return ret; 596 597 /* Old servers can't handle swapbuffers */ 598 if (!pdp->swapAvailable) { 599 __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height, 600 __DRI2_THROTTLE_SWAPBUFFER); 601 } else { 602#ifdef X_DRI2SwapBuffers 603#ifdef __DRI2_FLUSH 604 if (psc->f) { 605 struct glx_context *gc = __glXGetCurrentContext(); 606 607 if (gc) { 608 (*psc->f->flush)(priv->driDrawable); 609 } 610 } 611#endif 612 613 dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER); 614 615 DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, 616 target_msc, divisor, remainder, &ret); 617#endif 618 } 619 620 /* Old servers don't send invalidate events */ 621 if (!pdp->invalidateAvailable) 622 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable); 623 624 return ret; 625} 626 627static __DRIbuffer * 628dri2GetBuffers(__DRIdrawable * driDrawable, 629 int *width, int *height, 630 unsigned int *attachments, int count, 631 int *out_count, void *loaderPrivate) 632{ 633 struct dri2_drawable *pdraw = loaderPrivate; 634 DRI2Buffer *buffers; 635 636 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 637 width, height, attachments, count, out_count); 638 if (buffers == NULL) 639 return NULL; 640 641 pdraw->width = *width; 642 pdraw->height = *height; 643 process_buffers(pdraw, buffers, *out_count); 644 645 Xfree(buffers); 646 647 return pdraw->buffers; 648} 649 650static __DRIbuffer * 651dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 652 int *width, int *height, 653 unsigned int *attachments, int count, 654 int *out_count, void *loaderPrivate) 655{ 656 struct dri2_drawable *pdraw = loaderPrivate; 657 DRI2Buffer *buffers; 658 659 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 660 pdraw->base.xDrawable, 661 width, height, attachments, 662 count, out_count); 663 if (buffers == NULL) 664 return NULL; 665 666 pdraw->width = *width; 667 pdraw->height = *height; 668 process_buffers(pdraw, buffers, *out_count); 669 670 Xfree(buffers); 671 672 return pdraw->buffers; 673} 674 675#ifdef X_DRI2SwapInterval 676 677static int 678dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 679{ 680 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 681 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 682 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 683 684 if (psc->config) 685 psc->config->configQueryi(psc->driScreen, 686 "vblank_mode", &vblank_mode); 687 688 switch (vblank_mode) { 689 case DRI_CONF_VBLANK_NEVER: 690 return GLX_BAD_VALUE; 691 case DRI_CONF_VBLANK_ALWAYS_SYNC: 692 if (interval <= 0) 693 return GLX_BAD_VALUE; 694 break; 695 default: 696 break; 697 } 698 699 DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval); 700 priv->swap_interval = interval; 701 702 return 0; 703} 704 705static int 706dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 707{ 708 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 709 710 return priv->swap_interval; 711} 712 713#endif /* X_DRI2SwapInterval */ 714 715static const __DRIdri2LoaderExtension dri2LoaderExtension = { 716 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 717 dri2GetBuffers, 718 dri2FlushFrontBuffer, 719 dri2GetBuffersWithFormat, 720}; 721 722static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { 723 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 724 dri2GetBuffers, 725 dri2FlushFrontBuffer, 726 NULL, 727}; 728 729#ifdef __DRI_USE_INVALIDATE 730static const __DRIuseInvalidateExtension dri2UseInvalidate = { 731 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 732}; 733#endif 734 735_X_HIDDEN void 736dri2InvalidateBuffers(Display *dpy, XID drawable) 737{ 738 __GLXDRIdrawable *pdraw = 739 dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 740 struct dri2_screen *psc; 741 struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw; 742 743 if (!pdraw) 744 return; 745 746 psc = (struct dri2_screen *) pdraw->psc; 747 748#if __DRI2_FLUSH_VERSION >= 3 749 if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate) 750 psc->f->invalidate(pdp->driDrawable); 751#endif 752} 753 754static void 755dri2_bind_tex_image(Display * dpy, 756 GLXDrawable drawable, 757 int buffer, const int *attrib_list) 758{ 759 struct glx_context *gc = __glXGetCurrentContext(); 760 struct dri2_context *pcp = (struct dri2_context *) gc; 761 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 762 struct glx_display *dpyPriv = __glXInitialize(dpy); 763 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 764 struct dri2_display *pdp = 765 (struct dri2_display *) dpyPriv->dri2Display; 766 struct dri2_screen *psc; 767 768 if (pdraw != NULL) { 769 psc = (struct dri2_screen *) base->psc; 770 771#if __DRI2_FLUSH_VERSION >= 3 772 if (!pdp->invalidateAvailable && psc->f && 773 psc->f->base.version >= 3 && psc->f->invalidate) 774 psc->f->invalidate(pdraw->driDrawable); 775#endif 776 777 if (psc->texBuffer->base.version >= 2 && 778 psc->texBuffer->setTexBuffer2 != NULL) { 779 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 780 pdraw->base.textureTarget, 781 pdraw->base.textureFormat, 782 pdraw->driDrawable); 783 } 784 else { 785 (*psc->texBuffer->setTexBuffer) (pcp->driContext, 786 pdraw->base.textureTarget, 787 pdraw->driDrawable); 788 } 789 } 790} 791 792static void 793dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 794{ 795#if __DRI_TEX_BUFFER_VERSION >= 3 796 struct glx_context *gc = __glXGetCurrentContext(); 797 struct dri2_context *pcp = (struct dri2_context *) gc; 798 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 799 struct glx_display *dpyPriv = __glXInitialize(dpy); 800 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 801 struct dri2_display *pdp = 802 (struct dri2_display *) dpyPriv->dri2Display; 803 struct dri2_screen *psc; 804 805 if (pdraw != NULL) { 806 psc = (struct dri2_screen *) base->psc; 807 808 if (psc->texBuffer->base.version >= 3 && 809 psc->texBuffer->releaseTexBuffer != NULL) { 810 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 811 pdraw->base.textureTarget, 812 pdraw->driDrawable); 813 } 814 } 815#endif 816} 817 818static const struct glx_context_vtable dri2_context_vtable = { 819 dri2_destroy_context, 820 dri2_bind_context, 821 dri2_unbind_context, 822 dri2_wait_gl, 823 dri2_wait_x, 824 DRI_glXUseXFont, 825 dri2_bind_tex_image, 826 dri2_release_tex_image, 827 NULL, /* get_proc_address */ 828}; 829 830static void 831dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions) 832{ 833 int i; 834 835 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 836 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 837 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 838 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 839 840 /* FIXME: if DRI2 version supports it... */ 841 __glXEnableDirectExtension(&psc->base, "INTEL_swap_event"); 842 843 for (i = 0; extensions[i]; i++) { 844 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 845 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 846 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 847 } 848 849 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 850 psc->f = (__DRI2flushExtension *) extensions[i]; 851 /* internal driver extension, no GL extension exposed */ 852 } 853 854 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 855 psc->config = (__DRI2configQueryExtension *) extensions[i]; 856 857 if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0))) 858 psc->throttle = (__DRI2throttleExtension *) extensions[i]; 859 } 860} 861 862static const struct glx_screen_vtable dri2_screen_vtable = { 863 dri2_create_context 864}; 865 866static struct glx_screen * 867dri2CreateScreen(int screen, struct glx_display * priv) 868{ 869 const __DRIconfig **driver_configs; 870 const __DRIextension **extensions; 871 const struct dri2_display *const pdp = (struct dri2_display *) 872 priv->dri2Display; 873 struct dri2_screen *psc; 874 __GLXDRIscreen *psp; 875 struct glx_config *configs = NULL, *visuals = NULL; 876 char *driverName, *deviceName; 877 drm_magic_t magic; 878 int i; 879 880 psc = Xmalloc(sizeof *psc); 881 if (psc == NULL) 882 return NULL; 883 884 memset(psc, 0, sizeof *psc); 885 psc->fd = -1; 886 887 if (!glx_screen_init(&psc->base, screen, priv)) { 888 Xfree(psc); 889 return NULL; 890 } 891 892 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen), 893 &driverName, &deviceName)) { 894 glx_screen_cleanup(&psc->base); 895 XFree(psc); 896 InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen); 897 return NULL; 898 } 899 900 psc->driver = driOpenDriver(driverName); 901 if (psc->driver == NULL) { 902 ErrorMessageF("driver pointer missing\n"); 903 goto handle_error; 904 } 905 906 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 907 if (extensions == NULL) { 908 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 909 goto handle_error; 910 } 911 912 for (i = 0; extensions[i]; i++) { 913 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 914 psc->core = (__DRIcoreExtension *) extensions[i]; 915 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 916 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 917 } 918 919 if (psc->core == NULL || psc->dri2 == NULL) { 920 ErrorMessageF("core dri or dri2 extension not found\n"); 921 goto handle_error; 922 } 923 924 psc->fd = open(deviceName, O_RDWR); 925 if (psc->fd < 0) { 926 ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); 927 goto handle_error; 928 } 929 930 if (drmGetMagic(psc->fd, &magic)) { 931 ErrorMessageF("failed to get magic\n"); 932 goto handle_error; 933 } 934 935 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) { 936 ErrorMessageF("failed to authenticate magic %d\n", magic); 937 goto handle_error; 938 } 939 940 941 /* If the server does not support the protocol for 942 * DRI2GetBuffersWithFormat, don't supply that interface to the driver. 943 */ 944 psc->driScreen = 945 psc->dri2->createNewScreen(screen, psc->fd, 946 (const __DRIextension **) 947 &pdp->loader_extensions[0], 948 &driver_configs, psc); 949 950 if (psc->driScreen == NULL) { 951 ErrorMessageF("failed to create dri screen\n"); 952 goto handle_error; 953 } 954 955 extensions = psc->core->getExtensions(psc->driScreen); 956 dri2BindExtensions(psc, extensions); 957 958 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); 959 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 960 961 if (!configs || !visuals) 962 goto handle_error; 963 964 glx_config_destroy_list(psc->base.configs); 965 psc->base.configs = configs; 966 glx_config_destroy_list(psc->base.visuals); 967 psc->base.visuals = visuals; 968 969 psc->driver_configs = driver_configs; 970 971 psc->base.vtable = &dri2_screen_vtable; 972 psp = &psc->vtable; 973 psc->base.driScreen = psp; 974 psp->destroyScreen = dri2DestroyScreen; 975 psp->createDrawable = dri2CreateDrawable; 976 psp->swapBuffers = dri2SwapBuffers; 977 psp->getDrawableMSC = NULL; 978 psp->waitForMSC = NULL; 979 psp->waitForSBC = NULL; 980 psp->setSwapInterval = NULL; 981 psp->getSwapInterval = NULL; 982 983 if (pdp->driMinor >= 2) { 984#ifdef X_DRI2GetMSC 985 psp->getDrawableMSC = dri2DrawableGetMSC; 986#endif 987#ifdef X_DRI2WaitMSC 988 psp->waitForMSC = dri2WaitForMSC; 989 psp->waitForSBC = dri2WaitForSBC; 990#endif 991#ifdef X_DRI2SwapInterval 992 psp->setSwapInterval = dri2SetSwapInterval; 993 psp->getSwapInterval = dri2GetSwapInterval; 994#endif 995#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval) 996 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 997#endif 998 } 999 1000 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always 1001 * available.*/ 1002 psp->copySubBuffer = dri2CopySubBuffer; 1003 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 1004 1005 Xfree(driverName); 1006 Xfree(deviceName); 1007 1008 return &psc->base; 1009 1010handle_error: 1011 if (configs) 1012 glx_config_destroy_list(configs); 1013 if (visuals) 1014 glx_config_destroy_list(visuals); 1015 if (psc->driScreen) 1016 psc->core->destroyScreen(psc->driScreen); 1017 psc->driScreen = NULL; 1018 if (psc->fd >= 0) 1019 close(psc->fd); 1020 if (psc->driver) 1021 dlclose(psc->driver); 1022 1023 Xfree(driverName); 1024 Xfree(deviceName); 1025 glx_screen_cleanup(&psc->base); 1026 XFree(psc); 1027 1028 return NULL; 1029} 1030 1031/* Called from __glXFreeDisplayPrivate. 1032 */ 1033static void 1034dri2DestroyDisplay(__GLXDRIdisplay * dpy) 1035{ 1036 struct dri2_display *pdp = (struct dri2_display *) dpy; 1037 1038 __glxHashDestroy(pdp->dri2Hash); 1039 Xfree(dpy); 1040} 1041 1042_X_HIDDEN __GLXDRIdrawable * 1043dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 1044{ 1045 struct glx_display *d = __glXInitialize(dpy); 1046 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display; 1047 __GLXDRIdrawable *pdraw; 1048 1049 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) 1050 return pdraw; 1051 1052 return NULL; 1053} 1054 1055/* 1056 * Allocate, initialize and return a __DRIdisplayPrivate object. 1057 * This is called from __glXInitialize() when we are given a new 1058 * display pointer. 1059 */ 1060_X_HIDDEN __GLXDRIdisplay * 1061dri2CreateDisplay(Display * dpy) 1062{ 1063 struct dri2_display *pdp; 1064 int eventBase, errorBase, i; 1065 1066 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 1067 return NULL; 1068 1069 pdp = Xmalloc(sizeof *pdp); 1070 if (pdp == NULL) 1071 return NULL; 1072 1073 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { 1074 Xfree(pdp); 1075 return NULL; 1076 } 1077 1078 pdp->driPatch = 0; 1079 pdp->swapAvailable = (pdp->driMinor >= 2); 1080 pdp->invalidateAvailable = (pdp->driMinor >= 3); 1081 1082 pdp->base.destroyDisplay = dri2DestroyDisplay; 1083 pdp->base.createScreen = dri2CreateScreen; 1084 1085 i = 0; 1086 if (pdp->driMinor < 1) 1087 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base; 1088 else 1089 pdp->loader_extensions[i++] = &dri2LoaderExtension.base; 1090 1091 pdp->loader_extensions[i++] = &systemTimeExtension.base; 1092 1093#ifdef __DRI_USE_INVALIDATE 1094 pdp->loader_extensions[i++] = &dri2UseInvalidate.base; 1095#endif 1096 pdp->loader_extensions[i++] = NULL; 1097 1098 pdp->dri2Hash = __glxHashCreate(); 1099 if (pdp->dri2Hash == NULL) { 1100 Xfree(pdp); 1101 return NULL; 1102 } 1103 1104 return &pdp->base; 1105} 1106 1107#endif /* GLX_DIRECT_RENDERING */ 1108