dri_util.c revision a249ad756f72835c5894e389150207b98532e114
1/* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */ 2/** 3 * \file dri_util.c 4 * DRI utility functions. 5 * 6 * This module acts as glue between GLX and the actual hardware driver. A DRI 7 * driver doesn't really \e have to use any of this - it's optional. But, some 8 * useful stuff is done here that otherwise would have to be duplicated in most 9 * drivers. 10 * 11 * Basically, these utility functions take care of some of the dirty details of 12 * screen initialization, context creation, context binding, DRM setup, etc. 13 * 14 * These functions are compiled into each DRI driver so libGL.so knows nothing 15 * about them. 16 * 17 * \note 18 * When \c DRI_NEW_INTERFACE_ONLY is defined, code is built / not built so 19 * that only the "new" libGL-to-driver interfaces are supported. This breaks 20 * backwards compatability. However, this may be necessary when DRI drivers 21 * are built to be used in non-XFree86 environments. 22 * 23 * \todo There are still some places in the code that need to be wrapped with 24 * \c DRI_NEW_INTERFACE_ONLY. 25 */ 26 27 28#ifdef GLX_DIRECT_RENDERING 29 30#include <inttypes.h> 31#include <assert.h> 32#include <stdarg.h> 33#include <unistd.h> 34#include <sys/mman.h> 35#include <X11/Xlibint.h> 36#include <Xext.h> 37#include <extutil.h> 38#include <stdio.h> 39#include "dri_util.h" 40#include "xf86dri.h" 41#include "sarea.h" 42#include "glcontextmodes.h" 43 44/*#define DRI_NEW_INTERFACE_ONLY*/ 45 46#ifndef GLX_OML_sync_control 47typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); 48#endif 49 50/** 51 * This is used in a couple of places that call \c driCreateNewDrawable. 52 */ 53static const int empty_attribute_list[1] = { None }; 54 55/** 56 * Function used to determine if a drawable (window) still exists. Ideally 57 * this function comes from libGL. With older versions of libGL from XFree86 58 * we can fall-back to an internal version. 59 * 60 * \sa __driWindowExists __glXWindowExists 61 */ 62static PFNGLXWINDOWEXISTSPROC window_exists; 63 64typedef Bool (*PFNGLXCREATECONTEXTWITHCONFIGPROC)( Display*, int, int, void *, 65 drmContextPtr ); 66 67static PFNGLXCREATECONTEXTWITHCONFIGPROC create_context_with_config; 68 69/** 70 * Cached copy of the internal API version used by libGL and the client-side 71 * DRI driver. 72 */ 73static int api_ver = 0; 74 75/* forward declarations */ 76static int driQueryFrameTracking( Display * dpy, void * priv, 77 int64_t * sbc, int64_t * missedFrames, float * lastMissedUsage, 78 float * usage ); 79 80static void *driCreateNewDrawable(Display *dpy, const __GLcontextModes *modes, 81 GLXDrawable draw, __DRIdrawable *pdraw, int renderType, const int *attrs); 82 83static void driDestroyDrawable(Display *dpy, void *drawablePrivate); 84 85 86 87 88#ifdef not_defined 89static Bool driFeatureOn(const char *name) 90{ 91 char *env = getenv(name); 92 93 if (!env) return GL_FALSE; 94 if (!strcasecmp(env, "enable")) return GL_TRUE; 95 if (!strcasecmp(env, "1")) return GL_TRUE; 96 if (!strcasecmp(env, "on")) return GL_TRUE; 97 if (!strcasecmp(env, "true")) return GL_TRUE; 98 if (!strcasecmp(env, "t")) return GL_TRUE; 99 if (!strcasecmp(env, "yes")) return GL_TRUE; 100 if (!strcasecmp(env, "y")) return GL_TRUE; 101 102 return GL_FALSE; 103} 104#endif /* not_defined */ 105 106 107/** 108 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable 109 * is set. 110 * 111 * Is called from the drivers. 112 * 113 * \param f \c printf like format string. 114 */ 115void 116__driUtilMessage(const char *f, ...) 117{ 118 va_list args; 119 120 if (getenv("LIBGL_DEBUG")) { 121 fprintf(stderr, "libGL error: \n"); 122 va_start(args, f); 123 vfprintf(stderr, f, args); 124 va_end(args); 125 fprintf(stderr, "\n"); 126 } 127} 128 129 130/*****************************************************************/ 131/** \name Visual utility functions */ 132/*****************************************************************/ 133/*@{*/ 134 135#ifndef DRI_NEW_INTERFACE_ONLY 136/** 137 * Find a \c __GLcontextModes structure matching the given visual ID. 138 * 139 * \param dpy Display to search for a matching configuration. 140 * \param scrn Screen number on \c dpy to be searched. 141 * \param vid Desired \c VisualID to find. 142 * 143 * \returns A pointer to a \c __GLcontextModes structure that matches \c vid, 144 * if found, or \c NULL if no match is found. 145 */ 146static const __GLcontextModes * 147findConfigMode(Display *dpy, int scrn, VisualID vid, 148 const __DRIscreen * pDRIScreen) 149{ 150 if ( (pDRIScreen != NULL) && (pDRIScreen->private != NULL) ) { 151 const __DRIscreenPrivate * const psp = 152 (const __DRIscreenPrivate *) pDRIScreen->private; 153 154 return _gl_context_modes_find_visual( psp->modes, vid ); 155 } 156 157 return NULL; 158} 159 160 161/** 162 * This function is a hack to work-around old versions of libGL.so that 163 * do not export \c XF86DRICreateContextWithConfig. I would modify the 164 * code to just use this function, but the stand-alone driver (i.e., DRI 165 * drivers that are built to work without XFree86) shouldn't have to know 166 * about X structures like a \c Visual. 167 */ 168static Bool 169fake_XF86DRICreateContextWithConfig( Display* dpy, int screen, int configID, 170 XID* context, drmContextPtr hHWContext ) 171{ 172 Visual vis; 173 174 vis.visualid = configID; 175 return XF86DRICreateContext( dpy, screen, & vis, context, hHWContext ); 176} 177#endif /* DRI_NEW_INTERFACE_ONLY */ 178 179/*@}*/ 180 181 182/*****************************************************************/ 183/** \name Drawable list management */ 184/*****************************************************************/ 185/*@{*/ 186 187static Bool __driAddDrawable(void *drawHash, __DRIdrawable *pdraw) 188{ 189 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private; 190 191 if (drmHashInsert(drawHash, pdp->draw, pdraw)) 192 return GL_FALSE; 193 194 return GL_TRUE; 195} 196 197static __DRIdrawable *__driFindDrawable(void *drawHash, GLXDrawable draw) 198{ 199 int retcode; 200 __DRIdrawable *pdraw; 201 202 retcode = drmHashLookup(drawHash, draw, (void **)&pdraw); 203 if (retcode) 204 return NULL; 205 206 return pdraw; 207} 208 209static void __driRemoveDrawable(void *drawHash, __DRIdrawable *pdraw) 210{ 211 int retcode; 212 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private; 213 214 retcode = drmHashLookup(drawHash, pdp->draw, (void **)&pdraw); 215 if (!retcode) { /* Found */ 216 drmHashDelete(drawHash, pdp->draw); 217 } 218} 219 220#ifndef DRI_NEW_INTERFACE_ONLY 221static Bool __driWindowExistsFlag; 222 223static int __driWindowExistsErrorHandler(Display *dpy, XErrorEvent *xerr) 224{ 225 if (xerr->error_code == BadWindow) { 226 __driWindowExistsFlag = GL_FALSE; 227 } 228 return 0; 229} 230 231/** 232 * Determine if a window associated with a \c GLXDrawable exists on the 233 * X-server. 234 * 235 * \param dpy Display associated with the drawable to be queried. 236 * \param draw \c GLXDrawable to test. 237 * 238 * \returns \c GL_TRUE if a window exists that is associated with \c draw, 239 * otherwise \c GL_FALSE is returned. 240 * 241 * \warning This function is not currently thread-safe. 242 * 243 * \deprecated 244 * \c __glXWindowExists (from libGL) is prefered over this function. Starting 245 * with the next major release of XFree86, this function will be removed. 246 * Even now this function is no longer directly called. Instead it is called 247 * via a function pointer if and only if \c __glXWindowExists does not exist. 248 * 249 * \sa __glXWindowExists glXGetProcAddress window_exists 250 */ 251static Bool __driWindowExists(Display *dpy, GLXDrawable draw) 252{ 253 XWindowAttributes xwa; 254 int (*oldXErrorHandler)(Display *, XErrorEvent *); 255 256 XSync(dpy, GL_FALSE); 257 __driWindowExistsFlag = GL_TRUE; 258 oldXErrorHandler = XSetErrorHandler(__driWindowExistsErrorHandler); 259 XGetWindowAttributes(dpy, draw, &xwa); /* dummy request */ 260 XSetErrorHandler(oldXErrorHandler); 261 return __driWindowExistsFlag; 262} 263#endif /* DRI_NEW_INTERFACE_ONLY */ 264 265/** 266 * Find drawables in the local hash that have been destroyed on the 267 * server. 268 * 269 * \param drawHash Hash-table containing all know drawables. 270 */ 271static void __driGarbageCollectDrawables(void *drawHash) 272{ 273 GLXDrawable draw; 274 __DRIdrawable *pdraw; 275 Display *dpy; 276 277 if (drmHashFirst(drawHash, &draw, (void **)&pdraw)) { 278 do { 279 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private; 280 dpy = pdp->driScreenPriv->display; 281 if (! (*window_exists)(dpy, draw)) { 282 /* Destroy the local drawable data in the hash table, if the 283 drawable no longer exists in the Xserver */ 284 __driRemoveDrawable(drawHash, pdraw); 285 (*pdraw->destroyDrawable)(dpy, pdraw->private); 286 Xfree(pdraw); 287 } 288 } while (drmHashNext(drawHash, &draw, (void **)&pdraw)); 289 } 290} 291 292/*@}*/ 293 294 295/*****************************************************************/ 296/** \name Context (un)binding functions */ 297/*****************************************************************/ 298/*@{*/ 299 300/** 301 * Unbind context. 302 * 303 * \param dpy the display handle. 304 * \param scrn the screen number. 305 * \param draw drawable. 306 * \param read Current reading drawable. 307 * \param gc context. 308 * 309 * \return \c GL_TRUE on success, or \c GL_FALSE on failure. 310 * 311 * \internal 312 * This function calls __DriverAPIRec::UnbindContext, and then decrements 313 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful 314 * return. 315 * 316 * While casting the opaque private pointers associated with the parameters 317 * into their respective real types it also assures they are not \c NULL. 318 */ 319static Bool driUnbindContext3(Display *dpy, int scrn, 320 GLXDrawable draw, GLXDrawable read, 321 __DRIcontext *ctx) 322{ 323 __DRIscreen *pDRIScreen; 324 __DRIdrawable *pdraw; 325 __DRIdrawable *pread; 326 __DRIcontextPrivate *pcp; 327 __DRIscreenPrivate *psp; 328 __DRIdrawablePrivate *pdp; 329 __DRIdrawablePrivate *prp; 330 331 /* 332 ** Assume error checking is done properly in glXMakeCurrent before 333 ** calling driUnbindContext3. 334 */ 335 336 if (ctx == NULL || draw == None || read == None) { 337 /* ERROR!!! */ 338 return GL_FALSE; 339 } 340 341 pDRIScreen = __glXFindDRIScreen(dpy, scrn); 342 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 343 /* ERROR!!! */ 344 return GL_FALSE; 345 } 346 347 psp = (__DRIscreenPrivate *)pDRIScreen->private; 348 pcp = (__DRIcontextPrivate *)ctx->private; 349 350 pdraw = __driFindDrawable(psp->drawHash, draw); 351 if (!pdraw) { 352 /* ERROR!!! */ 353 return GL_FALSE; 354 } 355 pdp = (__DRIdrawablePrivate *)pdraw->private; 356 357 pread = __driFindDrawable(psp->drawHash, read); 358 if (!pread) { 359 /* ERROR!!! */ 360 return GL_FALSE; 361 } 362 prp = (__DRIdrawablePrivate *)pread->private; 363 364 365 /* Let driver unbind drawable from context */ 366 (*psp->DriverAPI.UnbindContext)(pcp); 367 368 369 if (pdp->refcount == 0) { 370 /* ERROR!!! */ 371 return GL_FALSE; 372 } 373 374 pdp->refcount--; 375 376 if (prp != pdp) { 377 if (prp->refcount == 0) { 378 /* ERROR!!! */ 379 return GL_FALSE; 380 } 381 382 prp->refcount--; 383 } 384 385 386 /* XXX this is disabled so that if we call SwapBuffers on an unbound 387 * window we can determine the last context bound to the window and 388 * use that context's lock. (BrianP, 2-Dec-2000) 389 */ 390#if 0 391 /* Unbind the drawable */ 392 pcp->driDrawablePriv = NULL; 393 pdp->driContextPriv = &psp->dummyContextPriv; 394#endif 395 396 return GL_TRUE; 397} 398 399 400/** 401 * This function takes both a read buffer and a draw buffer. This is needed 402 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 403 * function. 404 * 405 * \bug This function calls \c driCreateNewDrawable in two places with the 406 * \c renderType hard-coded to \c GLX_WINDOW_BIT. Some checking might 407 * be needed in those places when support for pbuffers and / or pixmaps 408 * is added. Is it safe to assume that the drawable is a window? 409 */ 410static Bool DoBindContext(Display *dpy, 411 GLXDrawable draw, GLXDrawable read, 412 __DRIcontext *ctx, const __GLcontextModes * modes, 413 __DRIscreenPrivate *psp) 414{ 415 __DRIdrawable *pdraw; 416 __DRIdrawablePrivate *pdp; 417 __DRIdrawable *pread; 418 __DRIdrawablePrivate *prp; 419 __DRIcontextPrivate * const pcp = ctx->private; 420 421 422 /* Find the _DRIdrawable which corresponds to the writing GLXDrawable */ 423 pdraw = __driFindDrawable(psp->drawHash, draw); 424 if (!pdraw) { 425 /* Allocate a new drawable */ 426 pdraw = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable)); 427 if (!pdraw) { 428 /* ERROR!!! */ 429 return GL_FALSE; 430 } 431 432 /* Create a new drawable */ 433 driCreateNewDrawable(dpy, modes, draw, pdraw, GLX_WINDOW_BIT, 434 empty_attribute_list); 435 if (!pdraw->private) { 436 /* ERROR!!! */ 437 Xfree(pdraw); 438 return GL_FALSE; 439 } 440 441 } 442 pdp = (__DRIdrawablePrivate *) pdraw->private; 443 444 /* Find the _DRIdrawable which corresponds to the reading GLXDrawable */ 445 if (read == draw) { 446 /* read buffer == draw buffer */ 447 prp = pdp; 448 } 449 else { 450 pread = __driFindDrawable(psp->drawHash, read); 451 if (!pread) { 452 /* Allocate a new drawable */ 453 pread = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable)); 454 if (!pread) { 455 /* ERROR!!! */ 456 return GL_FALSE; 457 } 458 459 /* Create a new drawable */ 460 driCreateNewDrawable(dpy, modes, read, pread, GLX_WINDOW_BIT, 461 empty_attribute_list); 462 if (!pread->private) { 463 /* ERROR!!! */ 464 Xfree(pread); 465 return GL_FALSE; 466 } 467 } 468 prp = (__DRIdrawablePrivate *) pread->private; 469 } 470 471 /* Bind the drawable to the context */ 472 pcp->driDrawablePriv = pdp; 473 pdp->driContextPriv = pcp; 474 pdp->refcount++; 475 if ( pdp != prp ) { 476 prp->refcount++; 477 } 478 479 /* 480 ** Now that we have a context associated with this drawable, we can 481 ** initialize the drawable information if has not been done before. 482 */ 483 if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) { 484 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 485 __driUtilUpdateDrawableInfo(pdp); 486 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 487 } 488 489 /* Call device-specific MakeCurrent */ 490 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); 491 492 return GL_TRUE; 493} 494 495 496/** 497 * This function takes both a read buffer and a draw buffer. This is needed 498 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 499 * function. 500 */ 501static Bool driBindContext3(Display *dpy, int scrn, 502 GLXDrawable draw, GLXDrawable read, 503 __DRIcontext * ctx) 504{ 505 __DRIscreen *pDRIScreen; 506 507 /* 508 ** Assume error checking is done properly in glXMakeCurrent before 509 ** calling driBindContext. 510 */ 511 512 if (ctx == NULL || draw == None || read == None) { 513 /* ERROR!!! */ 514 return GL_FALSE; 515 } 516 517 pDRIScreen = __glXFindDRIScreen(dpy, scrn); 518 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 519 /* ERROR!!! */ 520 return GL_FALSE; 521 } 522 523 return DoBindContext( dpy, draw, read, ctx, ctx->mode, 524 (__DRIscreenPrivate *)pDRIScreen->private ); 525} 526 527 528#ifndef DRI_NEW_INTERFACE_ONLY 529/** 530 * This function takes both a read buffer and a draw buffer. This is needed 531 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 532 * function. 533 */ 534static Bool driBindContext2(Display *dpy, int scrn, 535 GLXDrawable draw, GLXDrawable read, 536 GLXContext gc) 537{ 538 __DRIscreen *pDRIScreen; 539 const __GLcontextModes *modes; 540 541 /* 542 ** Assume error checking is done properly in glXMakeCurrent before 543 ** calling driBindContext. 544 */ 545 546 if (gc == NULL || draw == None || read == None) { 547 /* ERROR!!! */ 548 return GL_FALSE; 549 } 550 551 pDRIScreen = __glXFindDRIScreen(dpy, scrn); 552 modes = (driCompareGLXAPIVersion( 20040317 ) >= 0) 553 ? gc->driContext.mode 554 : findConfigMode( dpy, scrn, gc->vid, pDRIScreen ); 555 556 if ( modes == NULL ) { 557 /* ERROR!!! */ 558 return GL_FALSE; 559 } 560 561 /* findConfigMode will return NULL if the DRI screen or screen private 562 * are NULL. 563 */ 564 assert( (pDRIScreen != NULL) && (pDRIScreen->private != NULL) ); 565 566 return DoBindContext( dpy, draw, read, & gc->driContext, modes, 567 (__DRIscreenPrivate *)pDRIScreen->private ); 568} 569 570static Bool driUnbindContext2(Display *dpy, int scrn, 571 GLXDrawable draw, GLXDrawable read, 572 GLXContext gc) 573{ 574 return driUnbindContext3(dpy, scrn, draw, read, & gc->driContext); 575} 576 577/* 578 * Simply call bind with the same GLXDrawable for the read and draw buffers. 579 */ 580static Bool driBindContext(Display *dpy, int scrn, 581 GLXDrawable draw, GLXContext gc) 582{ 583 return driBindContext2(dpy, scrn, draw, draw, gc); 584} 585 586 587/* 588 * Simply call bind with the same GLXDrawable for the read and draw buffers. 589 */ 590static Bool driUnbindContext(Display *dpy, int scrn, 591 GLXDrawable draw, GLXContext gc, 592 int will_rebind) 593{ 594 (void) will_rebind; 595 return driUnbindContext2( dpy, scrn, draw, draw, gc ); 596} 597#endif /* DRI_NEW_INTERFACE_ONLY */ 598 599/*@}*/ 600 601 602/*****************************************************************/ 603/** \name Drawable handling functions */ 604/*****************************************************************/ 605/*@{*/ 606 607/** 608 * Update private drawable information. 609 * 610 * \param pdp pointer to the private drawable information to update. 611 * 612 * This function basically updates the __DRIdrawablePrivate struct's 613 * cliprect information by calling \c __DRIDrawablePrivate::getInfo. This is 614 * usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which 615 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If 616 * the values are different that means we have to update the clipping 617 * info. 618 */ 619void 620__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp) 621{ 622 __DRIscreenPrivate *psp; 623 __DRIcontextPrivate *pcp = pdp->driContextPriv; 624 625 if (!pcp || (pdp != pcp->driDrawablePriv)) { 626 /* ERROR!!! */ 627 return; 628 } 629 630 psp = pdp->driScreenPriv; 631 if (!psp) { 632 /* ERROR!!! */ 633 return; 634 } 635 636 if (pdp->pClipRects) { 637 Xfree(pdp->pClipRects); 638 } 639 640 if (pdp->pBackClipRects) { 641 Xfree(pdp->pBackClipRects); 642 } 643 644 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 645 646 if (!__driFindDrawable(psp->drawHash, pdp->draw) || 647 ! (*pdp->getInfo)(pdp->display, pdp->screen, pdp->draw, 648 &pdp->index, &pdp->lastStamp, 649 &pdp->x, &pdp->y, &pdp->w, &pdp->h, 650 &pdp->numClipRects, &pdp->pClipRects, 651 &pdp->backX, 652 &pdp->backY, 653 &pdp->numBackClipRects, 654 &pdp->pBackClipRects )) { 655 /* Error -- eg the window may have been destroyed. Keep going 656 * with no cliprects. 657 */ 658 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */ 659 pdp->numClipRects = 0; 660 pdp->pClipRects = NULL; 661 pdp->numBackClipRects = 0; 662 pdp->pBackClipRects = NULL; 663 } 664 else 665 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp); 666 667 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 668 669} 670 671/*@}*/ 672 673/*****************************************************************/ 674/** \name GLX callbacks */ 675/*****************************************************************/ 676/*@{*/ 677 678/** 679 * Swap buffers. 680 * 681 * \param dpy the display handle. 682 * \param drawablePrivate opaque pointer to the per-drawable private info. 683 * 684 * \internal 685 * This function calls __DRIdrawablePrivate::swapBuffers. 686 * 687 * Is called directly from glXSwapBuffers(). 688 */ 689static void driSwapBuffers( Display *dpy, void *drawablePrivate ) 690{ 691 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate; 692 dPriv->swapBuffers(dPriv); 693 (void) dpy; 694} 695 696/** 697 * Called directly from a number of higher-level GLX functions. 698 */ 699static int driGetMSC( void *screenPrivate, int64_t *msc ) 700{ 701 __DRIscreenPrivate *sPriv = (__DRIscreenPrivate *) screenPrivate; 702 703 return sPriv->DriverAPI.GetMSC( sPriv, msc ); 704} 705 706/** 707 * Called directly from a number of higher-level GLX functions. 708 */ 709static int driGetSBC( Display *dpy, void *drawablePrivate, int64_t *sbc ) 710{ 711 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate; 712 __DRIswapInfo sInfo; 713 int status; 714 715 716 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); 717 *sbc = sInfo.swap_count; 718 719 return status; 720} 721 722static int driWaitForSBC( Display * dpy, void *drawablePriv, 723 int64_t target_sbc, 724 int64_t * msc, int64_t * sbc ) 725{ 726 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 727 728 return dPriv->driScreenPriv->DriverAPI.WaitForSBC( dPriv, target_sbc, 729 msc, sbc ); 730} 731 732static int driWaitForMSC( Display * dpy, void *drawablePriv, 733 int64_t target_msc, 734 int64_t divisor, int64_t remainder, 735 int64_t * msc, int64_t * sbc ) 736{ 737 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 738 __DRIswapInfo sInfo; 739 int status; 740 741 742 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc, 743 divisor, remainder, 744 msc ); 745 746 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync 747 * is supported but GLX_OML_sync_control is not. Therefore, don't return 748 * an error value if GetSwapInfo() is not implemented. 749 */ 750 if ( status == 0 751 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) { 752 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); 753 *sbc = sInfo.swap_count; 754 } 755 756 return status; 757} 758 759static int64_t driSwapBuffersMSC( Display * dpy, void *drawablePriv, 760 int64_t target_msc, 761 int64_t divisor, int64_t remainder ) 762{ 763 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 764 765 return dPriv->driScreenPriv->DriverAPI.SwapBuffersMSC( dPriv, target_msc, 766 divisor, 767 remainder ); 768} 769 770 771/** 772 * This is called via __DRIscreenRec's createNewDrawable pointer. 773 */ 774static void *driCreateNewDrawable(Display *dpy, 775 const __GLcontextModes *modes, 776 GLXDrawable draw, 777 __DRIdrawable *pdraw, 778 int renderType, 779 const int *attrs) 780{ 781 __DRIscreen * const pDRIScreen = __glXFindDRIScreen(dpy, modes->screen); 782 __DRIscreenPrivate *psp; 783 __DRIdrawablePrivate *pdp; 784 785 786 /* Since pbuffers are not yet supported, no drawable attributes are 787 * supported either. 788 */ 789 (void) attrs; 790 791 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 792 return NULL; 793 } 794 795 pdp = (__DRIdrawablePrivate *)Xmalloc(sizeof(__DRIdrawablePrivate)); 796 if (!pdp) { 797 return NULL; 798 } 799 800 if (!XF86DRICreateDrawable(dpy, modes->screen, draw, &pdp->hHWDrawable)) { 801 Xfree(pdp); 802 return NULL; 803 } 804 805 pdp->draw = draw; 806 pdp->pdraw = pdraw; 807 pdp->refcount = 0; 808 pdp->pStamp = NULL; 809 pdp->lastStamp = 0; 810 pdp->index = 0; 811 pdp->x = 0; 812 pdp->y = 0; 813 pdp->w = 0; 814 pdp->h = 0; 815 pdp->numClipRects = 0; 816 pdp->numBackClipRects = 0; 817 pdp->pClipRects = NULL; 818 pdp->pBackClipRects = NULL; 819 pdp->display = dpy; 820 pdp->screen = modes->screen; 821 822 psp = (__DRIscreenPrivate *)pDRIScreen->private; 823 pdp->driScreenPriv = psp; 824 pdp->driContextPriv = &psp->dummyContextPriv; 825 826 pdp->getInfo = (GetDrawableInfo *) 827 glXGetProcAddress( (const GLubyte *) "__glXGetDrawableInfo" ); 828 if ( pdp->getInfo == NULL ) { 829 pdp->getInfo = XF86DRIGetDrawableInfo; 830 } 831 832 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, modes, 833 renderType == GLX_PIXMAP_BIT)) { 834 (void)XF86DRIDestroyDrawable(dpy, modes->screen, pdp->draw); 835 Xfree(pdp); 836 return NULL; 837 } 838 839 pdraw->private = pdp; 840 pdraw->destroyDrawable = driDestroyDrawable; 841 pdraw->swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */ 842 843 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) { 844 pdraw->getSBC = driGetSBC; 845 pdraw->waitForSBC = driWaitForSBC; 846 pdraw->waitForMSC = driWaitForMSC; 847 pdraw->swapBuffersMSC = driSwapBuffersMSC; 848 pdraw->frameTracking = NULL; 849 pdraw->queryFrameTracking = driQueryFrameTracking; 850 851 /* This special default value is replaced with the configured 852 * default value when the drawable is first bound to a direct 853 * rendering context. */ 854 pdraw->swap_interval = (unsigned)-1; 855 } 856 857 pdp->swapBuffers = psp->DriverAPI.SwapBuffers; 858 859 /* Add pdraw to drawable list */ 860 if (!__driAddDrawable(psp->drawHash, pdraw)) { 861 /* ERROR!!! */ 862 (*pdraw->destroyDrawable)(dpy, pdp); 863 Xfree(pdp); 864 pdp = NULL; 865 pdraw->private = NULL; 866 } 867 868 return (void *) pdp; 869} 870 871static __DRIdrawable *driGetDrawable(Display *dpy, GLXDrawable draw, 872 void *screenPrivate) 873{ 874 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate; 875 876 /* 877 ** Make sure this routine returns NULL if the drawable is not bound 878 ** to a direct rendering context! 879 */ 880 return __driFindDrawable(psp->drawHash, draw); 881} 882 883static void driDestroyDrawable(Display *dpy, void *drawablePrivate) 884{ 885 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *) drawablePrivate; 886 __DRIscreenPrivate *psp = pdp->driScreenPriv; 887 int scrn = psp->myNum; 888 889 if (pdp) { 890 (*psp->DriverAPI.DestroyBuffer)(pdp); 891 if ((*window_exists)(dpy, pdp->draw)) 892 (void)XF86DRIDestroyDrawable(dpy, scrn, pdp->draw); 893 if (pdp->pClipRects) { 894 Xfree(pdp->pClipRects); 895 pdp->pClipRects = NULL; 896 } 897 if (pdp->pBackClipRects) { 898 Xfree(pdp->pBackClipRects); 899 pdp->pBackClipRects = NULL; 900 } 901 Xfree(pdp); 902 } 903} 904 905/*@}*/ 906 907 908/*****************************************************************/ 909/** \name Context handling functions */ 910/*****************************************************************/ 911/*@{*/ 912 913/** 914 * Destroy the per-context private information. 915 * 916 * \param dpy the display handle. 917 * \param scrn the screen number. 918 * \param contextPrivate opaque pointer to the per-drawable private info. 919 * 920 * \internal 921 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls 922 * drmDestroyContext(), and finally frees \p contextPrivate. 923 */ 924static void driDestroyContext(Display *dpy, int scrn, void *contextPrivate) 925{ 926 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *) contextPrivate; 927 928 if (pcp) { 929 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); 930 __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash); 931 (void)XF86DRIDestroyContext(dpy, scrn, pcp->contextID); 932 Xfree(pcp); 933 } 934} 935 936 937/** 938 * Create the per-drawable private driver information. 939 * 940 * \param dpy The display handle. 941 * \param modes Mode used to create the new context. 942 * \param render_type Type of rendering target. \c GLX_RGBA is the only 943 * type likely to ever be supported for direct-rendering. 944 * \param sharedPrivate The shared context dependent methods or \c NULL if 945 * non-existent. 946 * \param pctx DRI context to receive the context dependent methods. 947 * 948 * \returns An opaque pointer to the per-context private information on 949 * success, or \c NULL on failure. 950 * 951 * \internal 952 * This function allocates and fills a __DRIcontextPrivateRec structure. It 953 * performs some device independent initialization and passes all the 954 * relevent information to __DriverAPIRec::CreateContext to create the 955 * context. 956 * 957 */ 958static void * 959driCreateNewContext(Display *dpy, const __GLcontextModes *modes, 960 int render_type, void *sharedPrivate, __DRIcontext *pctx) 961{ 962 __DRIscreen *pDRIScreen; 963 __DRIcontextPrivate *pcp; 964 __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate; 965 __DRIscreenPrivate *psp; 966 void * const shareCtx = (pshare != NULL) ? pshare->driverPrivate : NULL; 967 968 pDRIScreen = __glXFindDRIScreen(dpy, modes->screen); 969 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 970 /* ERROR!!! */ 971 return NULL; 972 } 973 974 psp = (__DRIscreenPrivate *)pDRIScreen->private; 975 976 pcp = (__DRIcontextPrivate *)Xmalloc(sizeof(__DRIcontextPrivate)); 977 if (!pcp) { 978 return NULL; 979 } 980 981 if (! (*create_context_with_config)(dpy, modes->screen, modes->fbconfigID, 982 &pcp->contextID, &pcp->hHWContext)) { 983 Xfree(pcp); 984 return NULL; 985 } 986 987 pcp->display = dpy; 988 pcp->driScreenPriv = psp; 989 pcp->driDrawablePriv = NULL; 990 991 /* When the first context is created for a screen, initialize a "dummy" 992 * context. 993 */ 994 995 if (!psp->dummyContextPriv.driScreenPriv) { 996 psp->dummyContextPriv.contextID = 0; 997 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context; 998 psp->dummyContextPriv.driScreenPriv = psp; 999 psp->dummyContextPriv.driDrawablePriv = NULL; 1000 psp->dummyContextPriv.driverPrivate = NULL; 1001 /* No other fields should be used! */ 1002 } 1003 1004 pctx->destroyContext = driDestroyContext; 1005#ifdef DRI_NEW_INTERFACE_ONLY 1006 pctx->bindContext = NULL; 1007 pctx->unbindContext = NULL; 1008 pctx->bindContext2 = NULL; 1009 pctx->unbindContext2 = NULL; 1010 pctx->bindContext3 = driBindContext3; 1011 pctx->unbindContext3 = driUnbindContext3; 1012#else 1013 pctx->bindContext = driBindContext; 1014 pctx->unbindContext = driUnbindContext; 1015 if ( driCompareGLXAPIVersion( 20030606 ) >= 0 ) { 1016 pctx->bindContext2 = driBindContext2; 1017 pctx->unbindContext2 = driUnbindContext2; 1018 } 1019 1020 if ( driCompareGLXAPIVersion( 20040415 ) >= 0 ) { 1021 pctx->bindContext3 = driBindContext3; 1022 pctx->unbindContext3 = driUnbindContext3; 1023 } 1024#endif 1025 1026 if ( !(*psp->DriverAPI.CreateContext)(modes, pcp, shareCtx) ) { 1027 (void)XF86DRIDestroyContext(dpy, modes->screen, pcp->contextID); 1028 Xfree(pcp); 1029 return NULL; 1030 } 1031 1032 __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash); 1033 1034 return pcp; 1035} 1036 1037 1038#ifndef DRI_NEW_INTERFACE_ONLY 1039/** 1040 * Create the per-drawable private driver information. 1041 * 1042 * \param dpy the display handle. 1043 * \param vis the visual information. 1044 * \param sharedPrivate the shared context dependent methods or \c NULL if 1045 * non-existent. 1046 * \param pctx will receive the context dependent methods. 1047 * 1048 * \returns a opaque pointer to the per-context private information on success, or \c NULL 1049 * on failure. 1050 * 1051 * \deprecated 1052 * This function has been replaced by \c driCreateNewContext. In drivers 1053 * built to work with XFree86, this function will continue to exist to support 1054 * older versions of libGL. Starting with the next major relelase of XFree86, 1055 * this function will be removed. 1056 * 1057 * \internal 1058 * This function allocates and fills a __DRIcontextPrivateRec structure. It 1059 * gets the visual, converts it into a __GLcontextModesRec and passes it 1060 * to __DriverAPIRec::CreateContext to create the context. 1061 */ 1062static void *driCreateContext(Display *dpy, XVisualInfo *vis, 1063 void *sharedPrivate, __DRIcontext *pctx) 1064{ 1065 __DRIscreen *pDRIScreen; 1066 const __GLcontextModes *modes; 1067 1068 pDRIScreen = __glXFindDRIScreen(dpy, vis->screen); 1069 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 1070 /* ERROR!!! */ 1071 return NULL; 1072 } 1073 1074 1075 /* Setup a __GLcontextModes struct corresponding to vis->visualid 1076 * and create the rendering context. 1077 */ 1078 1079 modes = findConfigMode(dpy, vis->screen, vis->visualid, pDRIScreen); 1080 return (modes == NULL) 1081 ? NULL 1082 : driCreateNewContext( dpy, modes, GLX_RGBA_TYPE, 1083 sharedPrivate, pctx ); 1084} 1085#endif /* DRI_NEW_INTERFACE_ONLY */ 1086 1087/*@}*/ 1088 1089 1090/*****************************************************************/ 1091/** \name Screen handling functions */ 1092/*****************************************************************/ 1093/*@{*/ 1094 1095/** 1096 * Destroy the per-screen private information. 1097 * 1098 * \param dpy the display handle. 1099 * \param scrn the screen number. 1100 * \param screenPrivate opaque pointer to the per-screen private information. 1101 * 1102 * \internal 1103 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls 1104 * drmClose(), and finally frees \p screenPrivate. 1105 */ 1106static void driDestroyScreen(Display *dpy, int scrn, void *screenPrivate) 1107{ 1108 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate; 1109 1110 if (psp) { 1111 /* No interaction with the X-server is possible at this point. This 1112 * routine is called after XCloseDisplay, so there is no protocol 1113 * stream open to the X-server anymore. 1114 */ 1115 1116 if (psp->DriverAPI.DestroyScreen) 1117 (*psp->DriverAPI.DestroyScreen)(psp); 1118 1119 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); 1120 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); 1121 Xfree(psp->pDevPriv); 1122 (void)drmClose(psp->fd); 1123 if ( psp->modes != NULL ) { 1124 _gl_context_modes_destroy( psp->modes ); 1125 } 1126 Xfree(psp); 1127 } 1128} 1129 1130 1131/** 1132 * Utility function used to create a new driver-private screen structure. 1133 * 1134 * \param dpy Display pointer 1135 * \param scrn Index of the screen 1136 * \param psc DRI screen data (not driver private) 1137 * \param modes Linked list of known display modes. This list is, at a 1138 * minimum, a list of modes based on the current display mode. 1139 * These roughly match the set of available X11 visuals, but it 1140 * need not be limited to X11! The calling libGL should create 1141 * a list that will inform the driver of the current display 1142 * mode (i.e., color buffer depth, depth buffer depth, etc.). 1143 * \param ddx_version Version of the 2D DDX. This may not be meaningful for 1144 * all drivers. 1145 * \param dri_version Version of the "server-side" DRI. 1146 * \param drm_version Version of the kernel DRM. 1147 * \param frame_buffer Data describing the location and layout of the 1148 * framebuffer. 1149 * \param pSAREA Pointer the the SAREA. 1150 * \param fd Device handle for the DRM. 1151 * \param internal_api_version Version of the internal interface between the 1152 * driver and libGL. 1153 * \param driverAPI Driver API functions used by other routines in dri_util.c. 1154 */ 1155__DRIscreenPrivate * 1156__driUtilCreateNewScreen(Display *dpy, int scrn, __DRIscreen *psc, 1157 __GLcontextModes * modes, 1158 const __DRIversion * ddx_version, 1159 const __DRIversion * dri_version, 1160 const __DRIversion * drm_version, 1161 const __DRIframebuffer * frame_buffer, 1162 drmAddress pSAREA, 1163 int fd, 1164 int internal_api_version, 1165 const struct __DriverAPIRec *driverAPI) 1166{ 1167 __DRIscreenPrivate *psp; 1168 1169 1170#ifdef DRI_NEW_INTERFACE_ONLY 1171 if ( internal_api_version < 20040415 ) { 1172 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. " 1173 "20040415 or later is required.\n", internal_api_version ); 1174 return NULL; 1175 } 1176#else 1177 if ( internal_api_version == 20031201 ) { 1178 fprintf( stderr, "libGL error: libGL version 20031201 has critical " 1179 "binary compatilibity bugs.\nlibGL error: You must upgrade " 1180 "to use direct-rendering!\n" ); 1181 return NULL; 1182 } 1183#endif /* DRI_NEW_INTERFACE_ONLY */ 1184 1185 1186 window_exists = (PFNGLXWINDOWEXISTSPROC) 1187 glXGetProcAddress( (const GLubyte *) "__glXWindowExists" ); 1188 1189 if ( window_exists == NULL ) { 1190#ifdef DRI_NEW_INTERFACE_ONLY 1191 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. " 1192 "20021128 or later is required.\n", internal_api_version ); 1193 return NULL; 1194#else 1195 window_exists = (PFNGLXWINDOWEXISTSPROC) __driWindowExists; 1196#endif /* DRI_NEW_INTERFACE_ONLY */ 1197 } 1198 1199 create_context_with_config = (PFNGLXCREATECONTEXTWITHCONFIGPROC) 1200 glXGetProcAddress( (const GLubyte *) "__glXCreateContextWithConfig" ); 1201 if ( create_context_with_config == NULL ) { 1202#ifdef DRI_NEW_INTERFACE_ONLY 1203 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. " 1204 "20031201 or later is required.\n", internal_api_version ); 1205 return NULL; 1206#else 1207 create_context_with_config = (PFNGLXCREATECONTEXTWITHCONFIGPROC) 1208 fake_XF86DRICreateContextWithConfig; 1209#endif /* DRI_NEW_INTERFACE_ONLY */ 1210 } 1211 1212 api_ver = internal_api_version; 1213 1214 psp = (__DRIscreenPrivate *)Xmalloc(sizeof(__DRIscreenPrivate)); 1215 if (!psp) { 1216 return NULL; 1217 } 1218 1219 /* Create the hash table */ 1220 psp->drawHash = drmHashCreate(); 1221 if ( psp->drawHash == NULL ) { 1222 Xfree( psp ); 1223 return NULL; 1224 } 1225 1226 psp->display = dpy; 1227 psp->myNum = scrn; 1228 psp->psc = psc; 1229 psp->modes = modes; 1230 1231 /* 1232 ** NOT_DONE: This is used by the X server to detect when the client 1233 ** has died while holding the drawable lock. The client sets the 1234 ** drawable lock to this value. 1235 */ 1236 psp->drawLockID = 1; 1237 1238 psp->drmMajor = drm_version->major; 1239 psp->drmMinor = drm_version->minor; 1240 psp->drmPatch = drm_version->patch; 1241 psp->ddxMajor = ddx_version->major; 1242 psp->ddxMinor = ddx_version->minor; 1243 psp->ddxPatch = ddx_version->patch; 1244 psp->driMajor = dri_version->major; 1245 psp->driMinor = dri_version->minor; 1246 psp->driPatch = dri_version->patch; 1247 1248 /* install driver's callback functions */ 1249 memcpy( &psp->DriverAPI, driverAPI, sizeof(struct __DriverAPIRec) ); 1250 1251 psp->pSAREA = pSAREA; 1252 1253 psp->pFB = frame_buffer->base; 1254 psp->fbSize = frame_buffer->size; 1255 psp->fbStride = frame_buffer->stride; 1256 psp->fbWidth = frame_buffer->width; 1257 psp->fbHeight = frame_buffer->height; 1258 psp->devPrivSize = frame_buffer->dev_priv_size; 1259 psp->pDevPriv = frame_buffer->dev_priv; 1260 1261 psp->fd = fd; 1262 1263 /* 1264 ** Do not init dummy context here; actual initialization will be 1265 ** done when the first DRI context is created. Init screen priv ptr 1266 ** to NULL to let CreateContext routine that it needs to be inited. 1267 */ 1268 psp->dummyContextPriv.driScreenPriv = NULL; 1269 1270 psc->destroyScreen = driDestroyScreen; 1271#ifndef DRI_NEW_INTERFACE_ONLY 1272 psc->createContext = driCreateContext; 1273#else 1274 psc->createContext = NULL; 1275#endif 1276 psc->createNewDrawable = driCreateNewDrawable; 1277 psc->getDrawable = driGetDrawable; 1278#ifdef DRI_NEW_INTERFACE_ONLY 1279 psc->getMSC = driGetMSC; 1280 psc->createNewContext = driCreateNewContext; 1281#else 1282 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) { 1283 psc->getMSC = driGetMSC; 1284 1285 if ( driCompareGLXAPIVersion( 20030824 ) >= 0 ) { 1286 psc->createNewContext = driCreateNewContext; 1287 } 1288 } 1289#endif 1290 1291 if ( (psp->DriverAPI.InitDriver != NULL) 1292 && !(*psp->DriverAPI.InitDriver)(psp) ) { 1293 Xfree( psp ); 1294 return NULL; 1295 } 1296 1297 1298 return psp; 1299} 1300 1301 1302#ifndef DRI_NEW_INTERFACE_ONLY 1303/** 1304 * Utility function used to create a new driver-private screen structure. 1305 * 1306 * \param dpy Display pointer. 1307 * \param scrn Index of the screen. 1308 * \param psc DRI screen data (not driver private) 1309 * \param numConfigs Number of visual configs pointed to by \c configs. 1310 * \param configs Array of GLXvisualConfigs exported by the 2D driver. 1311 * \param driverAPI Driver API functions used by other routines in dri_util.c. 1312 * 1313 * \deprecated 1314 * This function has been replaced by \c __driUtilCreateNewScreen. In drivers 1315 * built to work with XFree86, this function will continue to exist to support 1316 * older versions of libGL. Starting with the next major relelase of XFree86, 1317 * this function will be removed. 1318 */ 1319__DRIscreenPrivate * 1320__driUtilCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, 1321 int numConfigs, __GLXvisualConfig *configs, 1322 const struct __DriverAPIRec *driverAPI) 1323{ 1324 int directCapable; 1325 __DRIscreenPrivate *psp = NULL; 1326 drmHandle hSAREA; 1327 drmAddress pSAREA; 1328 char *BusID; 1329 __GLcontextModes *modes; 1330 __GLcontextModes *temp; 1331 int i; 1332 __DRIversion ddx_version; 1333 __DRIversion dri_version; 1334 __DRIversion drm_version; 1335 __DRIframebuffer framebuffer; 1336 int fd = -1; 1337 int status; 1338 const char * err_msg; 1339 const char * err_extra; 1340 1341 1342 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrn, &directCapable) 1343 || !directCapable) { 1344 return NULL; 1345 } 1346 1347 1348 /* Create the linked list of context modes, and populate it with the 1349 * GLX visual information passed in by libGL. 1350 */ 1351 1352 modes = _gl_context_modes_create( numConfigs, sizeof(__GLcontextModes) ); 1353 if ( modes == NULL ) { 1354 return NULL; 1355 } 1356 1357 temp = modes; 1358 for ( i = 0 ; i < numConfigs ; i++ ) { 1359 assert( temp != NULL ); 1360 _gl_copy_visual_to_context_mode( temp, & configs[i] ); 1361 temp->screen = scrn; 1362 1363 temp = temp->next; 1364 } 1365 1366 err_msg = "XF86DRIOpenConnection"; 1367 err_extra = NULL; 1368 1369 if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) { 1370 fd = drmOpen(NULL,BusID); 1371 Xfree(BusID); /* No longer needed */ 1372 1373 err_msg = "open DRM"; 1374 err_extra = strerror( -fd ); 1375 1376 if (fd >= 0) { 1377 drmMagic magic; 1378 1379 err_msg = "drmGetMagic"; 1380 err_extra = NULL; 1381 1382 if (!drmGetMagic(fd, &magic)) { 1383 drmVersionPtr version = drmGetVersion(fd); 1384 if (version) { 1385 drm_version.major = version->version_major; 1386 drm_version.minor = version->version_minor; 1387 drm_version.patch = version->version_patchlevel; 1388 drmFreeVersion(version); 1389 } 1390 else { 1391 drm_version.major = -1; 1392 drm_version.minor = -1; 1393 drm_version.patch = -1; 1394 } 1395 1396 err_msg = "XF86DRIAuthConnection"; 1397 if (XF86DRIAuthConnection(dpy, scrn, magic)) { 1398 char *driverName; 1399 1400 /* 1401 * Get device name (like "tdfx") and the ddx version numbers. 1402 * We'll check the version in each DRI driver's "createScreen" 1403 * function. 1404 */ 1405 err_msg = "XF86DRIGetClientDriverName"; 1406 if (XF86DRIGetClientDriverName(dpy, scrn, 1407 &ddx_version.major, 1408 &ddx_version.minor, 1409 &ddx_version.patch, 1410 &driverName)) { 1411 1412 /* No longer needed. */ 1413 Xfree( driverName ); 1414 1415 /* 1416 * Get the DRI X extension version. 1417 */ 1418 err_msg = "XF86DRIQueryVersion"; 1419 if (XF86DRIQueryVersion(dpy, 1420 &dri_version.major, 1421 &dri_version.minor, 1422 &dri_version.patch)) { 1423 drmHandle hFB; 1424 int junk; 1425 1426 /* 1427 * Get device-specific info. pDevPriv will point to a struct 1428 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) 1429 * that has information about the screen size, depth, pitch, 1430 * ancilliary buffers, DRM mmap handles, etc. 1431 */ 1432 err_msg = "XF86DRIGetDeviceInfo"; 1433 if (XF86DRIGetDeviceInfo(dpy, scrn, 1434 &hFB, 1435 &junk, 1436 &framebuffer.size, 1437 &framebuffer.stride, 1438 &framebuffer.dev_priv_size, 1439 &framebuffer.dev_priv)) { 1440 framebuffer.width = DisplayWidth(dpy, scrn); 1441 framebuffer.height = DisplayHeight(dpy, scrn); 1442 1443 /* 1444 * Map the framebuffer region. 1445 */ 1446 status = drmMap(fd, hFB, framebuffer.size, 1447 (drmAddressPtr)&framebuffer.base); 1448 1449 err_msg = "drmMap of framebuffer"; 1450 err_extra = strerror( -status ); 1451 1452 if ( status == 0 ) { 1453 /* 1454 * Map the SAREA region. Further mmap regions may be setup in 1455 * each DRI driver's "createScreen" function. 1456 */ 1457 status = drmMap(fd, hSAREA, SAREA_MAX, 1458 &pSAREA); 1459 1460 err_msg = "drmMap of sarea"; 1461 err_extra = strerror( -status ); 1462 1463 if ( status == 0 ) { 1464 PFNGLXGETINTERNALVERSIONPROC get_ver; 1465 1466 get_ver = (PFNGLXGETINTERNALVERSIONPROC) 1467 glXGetProcAddress( (const GLubyte *) "__glXGetInternalVersion" ); 1468 1469 err_msg = "InitDriver"; 1470 err_extra = NULL; 1471 psp = __driUtilCreateNewScreen( dpy, scrn, psc, modes, 1472 & ddx_version, 1473 & dri_version, 1474 & drm_version, 1475 & framebuffer, 1476 pSAREA, 1477 fd, 1478 (get_ver != NULL) ? (*get_ver)() : 1, 1479 driverAPI ); 1480 } 1481 } 1482 } 1483 } 1484 } 1485 } 1486 } 1487 } 1488 } 1489 1490 if ( psp == NULL ) { 1491 if ( pSAREA != MAP_FAILED ) { 1492 (void)drmUnmap(pSAREA, SAREA_MAX); 1493 } 1494 1495 if ( framebuffer.base != MAP_FAILED ) { 1496 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size); 1497 } 1498 1499 if ( framebuffer.dev_priv != NULL ) { 1500 Xfree(framebuffer.dev_priv); 1501 } 1502 1503 if ( fd >= 0 ) { 1504 (void)drmClose(fd); 1505 } 1506 1507 if ( modes != NULL ) { 1508 _gl_context_modes_destroy( modes ); 1509 } 1510 1511 (void)XF86DRICloseConnection(dpy, scrn); 1512 1513 if ( err_extra != NULL ) { 1514 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg, 1515 err_extra); 1516 } 1517 else { 1518 fprintf(stderr, "libGL error: %s failed\n", err_msg ); 1519 } 1520 1521 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n"); 1522 } 1523 1524 return psp; 1525} 1526#endif /* DRI_NEW_INTERFACE_ONLY */ 1527 1528 1529/** 1530 * Compare the current GLX API version with a driver supplied required version. 1531 * 1532 * The minimum required version is compared with the API version exported by 1533 * the \c __glXGetInternalVersion function (in libGL.so). 1534 * 1535 * \param required_version Minimum required internal GLX API version. 1536 * \return A tri-value return, as from strcmp is returned. A value less 1537 * than, equal to, or greater than zero will be returned if the 1538 * internal GLX API version is less than, equal to, or greater 1539 * than \c required_version. 1540 * 1541 * \sa __glXGetInternalVersion(). 1542 */ 1543int driCompareGLXAPIVersion( GLuint required_version ) 1544{ 1545 if ( api_ver > required_version ) { 1546 return 1; 1547 } 1548 else if ( api_ver == required_version ) { 1549 return 0; 1550 } 1551 1552 return -1; 1553} 1554 1555 1556static int 1557driQueryFrameTracking( Display * dpy, void * priv, 1558 int64_t * sbc, int64_t * missedFrames, 1559 float * lastMissedUsage, float * usage ) 1560{ 1561 static PFNGLXGETUSTPROC get_ust; 1562 __DRIswapInfo sInfo; 1563 int status; 1564 int64_t ust; 1565 __DRIdrawablePrivate * dpriv = (__DRIdrawablePrivate *) priv; 1566 1567 if ( get_ust == NULL ) { 1568 get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( (const GLubyte *) "__glXGetUST" ); 1569 } 1570 1571 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo ); 1572 if ( status == 0 ) { 1573 *sbc = sInfo.swap_count; 1574 *missedFrames = sInfo.swap_missed_count; 1575 *lastMissedUsage = sInfo.swap_missed_usage; 1576 1577 (*get_ust)( & ust ); 1578 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust ); 1579 } 1580 1581 return status; 1582} 1583 1584 1585/** 1586 * Calculate amount of swap interval used between GLX buffer swaps. 1587 * 1588 * The usage value, on the range [0,max], is the fraction of total swap 1589 * interval time used between GLX buffer swaps is calculated. 1590 * 1591 * \f$p = t_d / (i * t_r)\f$ 1592 * 1593 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the 1594 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time 1595 * required for a single vertical refresh period (as returned by \c 1596 * glXGetMscRateOML). 1597 * 1598 * See the documentation for the GLX_MESA_swap_frame_usage extension for more 1599 * details. 1600 * 1601 * \param dPriv Pointer to the private drawable structure. 1602 * \return If less than a single swap interval time period was required 1603 * between GLX buffer swaps, a number greater than 0 and less than 1604 * 1.0 is returned. If exactly one swap interval time period is 1605 * required, 1.0 is returned, and if more than one is required then 1606 * a number greater than 1.0 will be returned. 1607 * 1608 * \sa glXSwapIntervalSGI glXGetMscRateOML 1609 * 1610 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it 1611 * be possible to cache the sync rate? 1612 */ 1613float 1614driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust, 1615 int64_t current_ust ) 1616{ 1617 static PFNGLXGETMSCRATEOMLPROC get_msc_rate = NULL; 1618 int32_t n; 1619 int32_t d; 1620 int interval; 1621 float usage = 1.0; 1622 1623 1624 if ( get_msc_rate == NULL ) { 1625 get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) 1626 glXGetProcAddress( (const GLubyte *) "glXGetMscRateOML" ); 1627 } 1628 1629 if ( (get_msc_rate != NULL) 1630 && get_msc_rate( dPriv->display, dPriv->draw, &n, &d ) ) { 1631 interval = (dPriv->pdraw->swap_interval != 0) 1632 ? dPriv->pdraw->swap_interval : 1; 1633 1634 1635 /* We want to calculate 1636 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get 1637 * current_UST by calling __glXGetUST. last_swap_UST is stored in 1638 * dPriv->swap_ust. interval has already been calculated. 1639 * 1640 * The only tricky part is us_per_refresh. us_per_refresh is 1641 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it 1642 * around and say us_per_refresh = 1000000 * d / n. Since this goes in 1643 * the denominator of the final calculation, we calculate 1644 * (interval * 1000000 * d) and move n into the numerator. 1645 */ 1646 1647 usage = (current_ust - last_swap_ust); 1648 usage *= n; 1649 usage /= (interval * d); 1650 usage /= 1000000.0; 1651 } 1652 1653 return usage; 1654} 1655 1656/*@}*/ 1657 1658#endif /* GLX_DIRECT_RENDERING */ 1659