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