dri_util.c revision aceccda56b08338e217991e54607f1c9f18fc3e6
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 18 19#include <assert.h> 20#include <stdarg.h> 21#include <unistd.h> 22#include <sys/mman.h> 23#include <stdio.h> 24 25#ifndef MAP_FAILED 26#define MAP_FAILED ((void *)-1) 27#endif 28 29#include "imports.h" 30#define None 0 31 32#include "dri_util.h" 33#include "drm_sarea.h" 34 35#ifndef GLX_OML_sync_control 36typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator); 37#endif 38 39/* This pointer *must* be set by the driver's __driCreateNewScreen funciton! 40 */ 41const __DRIinterfaceMethods * dri_interface = NULL; 42 43/** 44 * This is used in a couple of places that call \c driCreateNewDrawable. 45 */ 46static const int empty_attribute_list[1] = { None }; 47 48 49/** 50 * Cached copy of the internal API version used by libGL and the client-side 51 * DRI driver. 52 */ 53static int api_ver = 0; 54 55/* forward declarations */ 56static int driQueryFrameTracking( void *priv, 57 int64_t *sbc, int64_t *missedFrames, 58 float *lastMissedUsage, float *usage ); 59 60static void *driCreateNewDrawable(__DRIscreen *screen, 61 const __GLcontextModes *modes, 62 __DRIid draw, __DRIdrawable *pdraw, 63 int renderType, const int *attrs); 64 65static void driDestroyDrawable(void *drawablePrivate); 66 67 68/** 69 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable 70 * is set. 71 * 72 * Is called from the drivers. 73 * 74 * \param f \c printf like format string. 75 */ 76void 77__driUtilMessage(const char *f, ...) 78{ 79 va_list args; 80 81 if (getenv("LIBGL_DEBUG")) { 82 fprintf(stderr, "libGL error: \n"); 83 va_start(args, f); 84 vfprintf(stderr, f, args); 85 va_end(args); 86 fprintf(stderr, "\n"); 87 } 88} 89 90 91/*****************************************************************/ 92/** \name Context (un)binding functions */ 93/*****************************************************************/ 94/*@{*/ 95 96/** 97 * Unbind context. 98 * 99 * \param scrn the screen. 100 * \param gc context. 101 * 102 * \return \c GL_TRUE on success, or \c GL_FALSE on failure. 103 * 104 * \internal 105 * This function calls __DriverAPIRec::UnbindContext, and then decrements 106 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful 107 * return. 108 * 109 * While casting the opaque private pointers associated with the parameters 110 * into their respective real types it also assures they are not \c NULL. 111 */ 112static GLboolean driUnbindContext(__DRIcontext *ctx) 113{ 114 __DRIcontextPrivate *pcp; 115 __DRIscreenPrivate *psp; 116 __DRIdrawablePrivate *pdp; 117 __DRIdrawablePrivate *prp; 118 119 /* 120 ** Assume error checking is done properly in glXMakeCurrent before 121 ** calling driUnbindContext. 122 */ 123 124 if (ctx == NULL) 125 return GL_FALSE; 126 127 pcp = (__DRIcontextPrivate *)ctx->private; 128 psp = (__DRIscreenPrivate *)pcp->driScreenPriv; 129 pdp = (__DRIdrawablePrivate *)pcp->driDrawablePriv; 130 prp = (__DRIdrawablePrivate *)pcp->driReadablePriv; 131 132 /* Let driver unbind drawable from context */ 133 (*psp->DriverAPI.UnbindContext)(pcp); 134 135 if (pdp->refcount == 0) { 136 /* ERROR!!! */ 137 return GL_FALSE; 138 } 139 140 pdp->refcount--; 141 142 if (prp != pdp) { 143 if (prp->refcount == 0) { 144 /* ERROR!!! */ 145 return GL_FALSE; 146 } 147 148 prp->refcount--; 149 } 150 151 152 /* XXX this is disabled so that if we call SwapBuffers on an unbound 153 * window we can determine the last context bound to the window and 154 * use that context's lock. (BrianP, 2-Dec-2000) 155 */ 156#if 0 157 /* Unbind the drawable */ 158 pcp->driDrawablePriv = NULL; 159 pdp->driContextPriv = &psp->dummyContextPriv; 160#endif 161 162 return GL_TRUE; 163} 164 165 166/** 167 * This function takes both a read buffer and a draw buffer. This is needed 168 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 169 * function. 170 */ 171static GLboolean DoBindContext(__DRIdrawable *pdraw, 172 __DRIdrawable *pread, 173 __DRIcontext *ctx) 174{ 175 __DRIdrawablePrivate *pdp; 176 __DRIdrawablePrivate *prp; 177 __DRIcontextPrivate * const pcp = ctx->private; 178 __DRIscreenPrivate *psp = pcp->driScreenPriv; 179 180 pdp = (__DRIdrawablePrivate *) pdraw->private; 181 prp = (__DRIdrawablePrivate *) pread->private; 182 183 /* Bind the drawable to the context */ 184 pcp->driDrawablePriv = pdp; 185 pcp->driReadablePriv = prp; 186 pdp->driContextPriv = pcp; 187 pdp->refcount++; 188 if ( pdp != prp ) { 189 prp->refcount++; 190 } 191 192 /* 193 ** Now that we have a context associated with this drawable, we can 194 ** initialize the drawable information if has not been done before. 195 */ 196 if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) { 197 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 198 __driUtilUpdateDrawableInfo(pdp); 199 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 200 } 201 202 if ((pdp != prp) && (!prp->pStamp || *prp->pStamp != prp->lastStamp)) { 203 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 204 __driUtilUpdateDrawableInfo(prp); 205 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 206 } 207 208 /* Call device-specific MakeCurrent */ 209 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); 210 211 return GL_TRUE; 212} 213 214 215/** 216 * This function takes both a read buffer and a draw buffer. This is needed 217 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 218 * function. 219 */ 220static GLboolean driBindContext(__DRIdrawable *pdraw, 221 __DRIdrawable *pread, 222 __DRIcontext * ctx) 223{ 224 /* 225 ** Assume error checking is done properly in glXMakeCurrent before 226 ** calling driBindContext. 227 */ 228 229 if (ctx == NULL || pdraw == None || pread == None) 230 return GL_FALSE; 231 232 return DoBindContext( pdraw, pread, ctx ); 233} 234/*@}*/ 235 236 237/*****************************************************************/ 238/** \name Drawable handling functions */ 239/*****************************************************************/ 240/*@{*/ 241 242/** 243 * Update private drawable information. 244 * 245 * \param pdp pointer to the private drawable information to update. 246 * 247 * This function basically updates the __DRIdrawablePrivate struct's 248 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo. 249 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which 250 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If 251 * the values are different that means we have to update the clipping 252 * info. 253 */ 254void 255__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp) 256{ 257 __DRIscreenPrivate *psp; 258 __DRIcontextPrivate *pcp = pdp->driContextPriv; 259 260 if (!pcp 261 || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) { 262 /* ERROR!!! 263 * ...but we must ignore it. There can be many contexts bound to a 264 * drawable. 265 */ 266 } 267 268 psp = pdp->driScreenPriv; 269 if (!psp) { 270 /* ERROR!!! */ 271 _mesa_problem(NULL, "Warning! Possible infinite loop due to bug " 272 "in file %s, line %d\n", 273 __FILE__, __LINE__); 274 return; 275 } 276 277 if (pdp->pClipRects) { 278 _mesa_free(pdp->pClipRects); 279 pdp->pClipRects = NULL; 280 } 281 282 if (pdp->pBackClipRects) { 283 _mesa_free(pdp->pBackClipRects); 284 pdp->pBackClipRects = NULL; 285 } 286 287 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 288 289 if (! (*dri_interface->getDrawableInfo)(pdp->driScreenPriv->psc, pdp->draw, 290 &pdp->index, &pdp->lastStamp, 291 &pdp->x, &pdp->y, &pdp->w, &pdp->h, 292 &pdp->numClipRects, &pdp->pClipRects, 293 &pdp->backX, 294 &pdp->backY, 295 &pdp->numBackClipRects, 296 &pdp->pBackClipRects )) { 297 /* Error -- eg the window may have been destroyed. Keep going 298 * with no cliprects. 299 */ 300 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */ 301 pdp->numClipRects = 0; 302 pdp->pClipRects = NULL; 303 pdp->numBackClipRects = 0; 304 pdp->pBackClipRects = NULL; 305 } 306 else 307 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp); 308 309 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 310 311} 312 313/*@}*/ 314 315/*****************************************************************/ 316/** \name GLX callbacks */ 317/*****************************************************************/ 318/*@{*/ 319 320/** 321 * Swap buffers. 322 * 323 * \param drawablePrivate opaque pointer to the per-drawable private info. 324 * 325 * \internal 326 * This function calls __DRIdrawablePrivate::swapBuffers. 327 * 328 * Is called directly from glXSwapBuffers(). 329 */ 330static void driSwapBuffers(void *drawablePrivate) 331{ 332 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate; 333 drm_clip_rect_t rect; 334 335 dPriv->swapBuffers(dPriv); 336 337 /* Check that we actually have the new damage report method */ 338 if (api_ver < 20070105 || dri_interface->reportDamage == NULL) 339 return; 340 341 /* Assume it's affecting the whole drawable for now */ 342 rect.x1 = 0; 343 rect.y1 = 0; 344 rect.x2 = rect.x1 + dPriv->w; 345 rect.y2 = rect.y1 + dPriv->h; 346 347 /* Report the damage. Currently, all our drivers draw directly to the 348 * front buffer, so we report the damage there rather than to the backing 349 * store (if any). 350 */ 351 (*dri_interface->reportDamage)(dPriv->pdraw, dPriv->x, dPriv->y, 352 &rect, 1, GL_TRUE); 353} 354 355/** 356 * Called directly from a number of higher-level GLX functions. 357 */ 358static int driGetMSC( void *screenPrivate, int64_t *msc ) 359{ 360 __DRIscreenPrivate *sPriv = (__DRIscreenPrivate *) screenPrivate; 361 362 return sPriv->DriverAPI.GetMSC( sPriv, msc ); 363} 364 365/** 366 * Called directly from a number of higher-level GLX functions. 367 */ 368static int driGetSBC( void *drawablePrivate, int64_t *sbc ) 369{ 370 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate; 371 __DRIswapInfo sInfo; 372 int status; 373 374 375 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); 376 *sbc = sInfo.swap_count; 377 378 return status; 379} 380 381static int driWaitForSBC( void *drawablePriv, int64_t target_sbc, 382 int64_t * msc, int64_t * sbc ) 383{ 384 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 385 386 return dPriv->driScreenPriv->DriverAPI.WaitForSBC( dPriv, target_sbc, 387 msc, sbc ); 388} 389 390static int driWaitForMSC( void *drawablePriv, int64_t target_msc, 391 int64_t divisor, int64_t remainder, 392 int64_t * msc, int64_t * sbc ) 393{ 394 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 395 __DRIswapInfo sInfo; 396 int status; 397 398 399 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc, 400 divisor, remainder, 401 msc ); 402 403 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync 404 * is supported but GLX_OML_sync_control is not. Therefore, don't return 405 * an error value if GetSwapInfo() is not implemented. 406 */ 407 if ( status == 0 408 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) { 409 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); 410 *sbc = sInfo.swap_count; 411 } 412 413 return status; 414} 415 416static int64_t driSwapBuffersMSC( void *drawablePriv, int64_t target_msc, 417 int64_t divisor, int64_t remainder ) 418{ 419 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 420 421 return dPriv->driScreenPriv->DriverAPI.SwapBuffersMSC( dPriv, target_msc, 422 divisor, 423 remainder ); 424} 425 426static void driCopySubBuffer( void *drawablePrivate, 427 int x, int y, int w, int h) 428{ 429 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate; 430 dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h); 431} 432 433/** 434 * This is called via __DRIscreenRec's createNewDrawable pointer. 435 */ 436static void *driCreateNewDrawable(__DRIscreen *screen, 437 const __GLcontextModes *modes, 438 __DRIid draw, 439 __DRIdrawable *pdraw, 440 int renderType, 441 const int *attrs) 442{ 443 __DRIscreenPrivate *psp; 444 __DRIdrawablePrivate *pdp; 445 446 447 pdraw->private = NULL; 448 449 /* Since pbuffers are not yet supported, no drawable attributes are 450 * supported either. 451 */ 452 (void) attrs; 453 454 pdp = (__DRIdrawablePrivate *)_mesa_malloc(sizeof(__DRIdrawablePrivate)); 455 if (!pdp) { 456 return NULL; 457 } 458 459 /* Ensure that modes->screen and screen are the same screen? */ 460 461 if (!(*dri_interface->createDrawable)(screen, draw, &pdp->hHWDrawable)) { 462 _mesa_free(pdp); 463 return NULL; 464 } 465 466 pdp->draw = draw; 467 pdp->pdraw = pdraw; 468 pdp->refcount = 0; 469 pdp->pStamp = NULL; 470 pdp->lastStamp = 0; 471 pdp->index = 0; 472 pdp->x = 0; 473 pdp->y = 0; 474 pdp->w = 0; 475 pdp->h = 0; 476 pdp->numClipRects = 0; 477 pdp->numBackClipRects = 0; 478 pdp->pClipRects = NULL; 479 pdp->pBackClipRects = NULL; 480 481 psp = (__DRIscreenPrivate *)screen->private; 482 pdp->driScreenPriv = psp; 483 pdp->driContextPriv = &psp->dummyContextPriv; 484 485 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, modes, 486 renderType == GLX_PIXMAP_BIT)) { 487 (void)(*dri_interface->destroyDrawable)(screen, pdp->draw); 488 _mesa_free(pdp); 489 return NULL; 490 } 491 492 pdraw->private = pdp; 493 pdraw->destroyDrawable = driDestroyDrawable; 494 pdraw->swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */ 495 496 pdraw->getSBC = driGetSBC; 497 pdraw->waitForSBC = driWaitForSBC; 498 pdraw->waitForMSC = driWaitForMSC; 499 pdraw->swapBuffersMSC = driSwapBuffersMSC; 500 pdraw->frameTracking = NULL; 501 pdraw->queryFrameTracking = driQueryFrameTracking; 502 503 if (driCompareGLXAPIVersion (20060314) >= 0) 504 pdraw->copySubBuffer = driCopySubBuffer; 505 506 /* This special default value is replaced with the configured 507 * default value when the drawable is first bound to a direct 508 * rendering context. 509 */ 510 pdraw->swap_interval = (unsigned)-1; 511 512 pdp->swapBuffers = psp->DriverAPI.SwapBuffers; 513 514 return (void *) pdp; 515} 516 517static void 518driDestroyDrawable(void *drawablePrivate) 519{ 520 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *) drawablePrivate; 521 __DRIscreenPrivate *psp; 522 523 if (pdp) { 524 psp = pdp->driScreenPriv; 525 (*psp->DriverAPI.DestroyBuffer)(pdp); 526 (void)(*dri_interface->destroyDrawable)(psp->psc, pdp->draw); 527 if (pdp->pClipRects) { 528 _mesa_free(pdp->pClipRects); 529 pdp->pClipRects = NULL; 530 } 531 if (pdp->pBackClipRects) { 532 _mesa_free(pdp->pBackClipRects); 533 pdp->pBackClipRects = NULL; 534 } 535 _mesa_free(pdp); 536 } 537} 538 539/*@}*/ 540 541 542/*****************************************************************/ 543/** \name Context handling functions */ 544/*****************************************************************/ 545/*@{*/ 546 547/** 548 * Destroy the per-context private information. 549 * 550 * \param contextPrivate opaque pointer to the per-drawable private info. 551 * 552 * \internal 553 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls 554 * drmDestroyContext(), and finally frees \p contextPrivate. 555 */ 556static void 557driDestroyContext(void *contextPrivate) 558{ 559 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *) contextPrivate; 560 561 if (pcp) { 562 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); 563 (void) (*dri_interface->destroyContext)(pcp->driScreenPriv->psc, 564 pcp->contextID); 565 _mesa_free(pcp); 566 } 567} 568 569 570/** 571 * Create the per-drawable private driver information. 572 * 573 * \param dpy The display handle. 574 * \param modes Mode used to create the new context. 575 * \param render_type Type of rendering target. \c GLX_RGBA is the only 576 * type likely to ever be supported for direct-rendering. 577 * \param sharedPrivate The shared context dependent methods or \c NULL if 578 * non-existent. 579 * \param pctx DRI context to receive the context dependent methods. 580 * 581 * \returns An opaque pointer to the per-context private information on 582 * success, or \c NULL on failure. 583 * 584 * \internal 585 * This function allocates and fills a __DRIcontextPrivateRec structure. It 586 * performs some device independent initialization and passes all the 587 * relevent information to __DriverAPIRec::CreateContext to create the 588 * context. 589 * 590 */ 591static void * 592driCreateNewContext(__DRIscreen *screen, const __GLcontextModes *modes, 593 int render_type, void *sharedPrivate, __DRIcontext *pctx) 594{ 595 __DRIcontextPrivate *pcp; 596 __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate; 597 __DRIscreenPrivate *psp; 598 void * const shareCtx = (pshare != NULL) ? pshare->driverPrivate : NULL; 599 600 psp = (__DRIscreenPrivate *)screen->private; 601 602 pcp = (__DRIcontextPrivate *)_mesa_malloc(sizeof(__DRIcontextPrivate)); 603 if (!pcp) { 604 return NULL; 605 } 606 607 if (! (*dri_interface->createContext)(screen, modes->fbconfigID, 608 &pcp->contextID, &pcp->hHWContext)) { 609 _mesa_free(pcp); 610 return NULL; 611 } 612 613 pcp->driScreenPriv = psp; 614 pcp->driDrawablePriv = NULL; 615 616 /* When the first context is created for a screen, initialize a "dummy" 617 * context. 618 */ 619 620 if (!psp->dummyContextPriv.driScreenPriv) { 621 psp->dummyContextPriv.contextID = 0; 622 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context; 623 psp->dummyContextPriv.driScreenPriv = psp; 624 psp->dummyContextPriv.driDrawablePriv = NULL; 625 psp->dummyContextPriv.driverPrivate = NULL; 626 /* No other fields should be used! */ 627 } 628 629 pctx->destroyContext = driDestroyContext; 630 pctx->bindContext = driBindContext; 631 pctx->unbindContext = driUnbindContext; 632 633 if ( !(*psp->DriverAPI.CreateContext)(modes, pcp, shareCtx) ) { 634 (void) (*dri_interface->destroyContext)(screen, pcp->contextID); 635 _mesa_free(pcp); 636 return NULL; 637 } 638 639 return pcp; 640} 641/*@}*/ 642 643 644/*****************************************************************/ 645/** \name Screen handling functions */ 646/*****************************************************************/ 647/*@{*/ 648 649/** 650 * Destroy the per-screen private information. 651 * 652 * \param dpy the display handle. 653 * \param scrn the screen number. 654 * \param screenPrivate opaque pointer to the per-screen private information. 655 * 656 * \internal 657 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls 658 * drmClose(), and finally frees \p screenPrivate. 659 */ 660static void driDestroyScreen(void *screenPrivate) 661{ 662 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate; 663 664 if (psp) { 665 /* No interaction with the X-server is possible at this point. This 666 * routine is called after XCloseDisplay, so there is no protocol 667 * stream open to the X-server anymore. 668 */ 669 670 if (psp->DriverAPI.DestroyScreen) 671 (*psp->DriverAPI.DestroyScreen)(psp); 672 673 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); 674 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); 675 (void)drmCloseOnce(psp->fd); 676 if ( psp->modes != NULL ) { 677 (*dri_interface->destroyContextModes)( psp->modes ); 678 } 679 680 _mesa_free(psp); 681 } 682} 683 684 685/** 686 * Utility function used to create a new driver-private screen structure. 687 * 688 * \param dpy Display pointer 689 * \param scrn Index of the screen 690 * \param psc DRI screen data (not driver private) 691 * \param modes Linked list of known display modes. This list is, at a 692 * minimum, a list of modes based on the current display mode. 693 * These roughly match the set of available X11 visuals, but it 694 * need not be limited to X11! The calling libGL should create 695 * a list that will inform the driver of the current display 696 * mode (i.e., color buffer depth, depth buffer depth, etc.). 697 * \param ddx_version Version of the 2D DDX. This may not be meaningful for 698 * all drivers. 699 * \param dri_version Version of the "server-side" DRI. 700 * \param drm_version Version of the kernel DRM. 701 * \param frame_buffer Data describing the location and layout of the 702 * framebuffer. 703 * \param pSAREA Pointer the the SAREA. 704 * \param fd Device handle for the DRM. 705 * \param internal_api_version Version of the internal interface between the 706 * driver and libGL. 707 * \param driverAPI Driver API functions used by other routines in dri_util.c. 708 * 709 * \note 710 * There is no need to check the minimum API version in this function. Since 711 * the \c __driCreateNewScreen function is versioned, it is impossible for a 712 * loader that is too old to even load this driver. 713 */ 714__DRIscreenPrivate * 715__driUtilCreateNewScreen(int scr, __DRIscreen *psc, 716 __GLcontextModes * modes, 717 const __DRIversion * ddx_version, 718 const __DRIversion * dri_version, 719 const __DRIversion * drm_version, 720 const __DRIframebuffer * frame_buffer, 721 drm_sarea_t *pSAREA, 722 int fd, 723 int internal_api_version, 724 const struct __DriverAPIRec *driverAPI) 725{ 726 __DRIscreenPrivate *psp; 727 728 729 api_ver = internal_api_version; 730 731 psp = (__DRIscreenPrivate *)_mesa_malloc(sizeof(__DRIscreenPrivate)); 732 if (!psp) { 733 return NULL; 734 } 735 736 psp->psc = psc; 737 psp->modes = modes; 738 739 /* 740 ** NOT_DONE: This is used by the X server to detect when the client 741 ** has died while holding the drawable lock. The client sets the 742 ** drawable lock to this value. 743 */ 744 psp->drawLockID = 1; 745 746 psp->drmMajor = drm_version->major; 747 psp->drmMinor = drm_version->minor; 748 psp->drmPatch = drm_version->patch; 749 psp->ddxMajor = ddx_version->major; 750 psp->ddxMinor = ddx_version->minor; 751 psp->ddxPatch = ddx_version->patch; 752 psp->driMajor = dri_version->major; 753 psp->driMinor = dri_version->minor; 754 psp->driPatch = dri_version->patch; 755 756 /* install driver's callback functions */ 757 memcpy( &psp->DriverAPI, driverAPI, sizeof(struct __DriverAPIRec) ); 758 759 psp->pSAREA = pSAREA; 760 761 psp->pFB = frame_buffer->base; 762 psp->fbSize = frame_buffer->size; 763 psp->fbStride = frame_buffer->stride; 764 psp->fbWidth = frame_buffer->width; 765 psp->fbHeight = frame_buffer->height; 766 psp->devPrivSize = frame_buffer->dev_priv_size; 767 psp->pDevPriv = frame_buffer->dev_priv; 768 psp->fbBPP = psp->fbStride * 8 / frame_buffer->width; 769 770 psp->fd = fd; 771 psp->myNum = scr; 772 773 /* 774 ** Do not init dummy context here; actual initialization will be 775 ** done when the first DRI context is created. Init screen priv ptr 776 ** to NULL to let CreateContext routine that it needs to be inited. 777 */ 778 psp->dummyContextPriv.driScreenPriv = NULL; 779 780 psc->destroyScreen = driDestroyScreen; 781 psc->createNewDrawable = driCreateNewDrawable; 782 psc->getMSC = driGetMSC; 783 psc->createNewContext = driCreateNewContext; 784 785 if (internal_api_version >= 20070121) 786 psc->setTexOffset = psp->DriverAPI.setTexOffset; 787 788 if ( (psp->DriverAPI.InitDriver != NULL) 789 && !(*psp->DriverAPI.InitDriver)(psp) ) { 790 _mesa_free( psp ); 791 return NULL; 792 } 793 794 795 return psp; 796} 797 798 799/** 800 * Compare the current GLX API version with a driver supplied required version. 801 * 802 * The minimum required version is compared with the API version exported by 803 * the \c __glXGetInternalVersion function (in libGL.so). 804 * 805 * \param required_version Minimum required internal GLX API version. 806 * \return A tri-value return, as from strcmp is returned. A value less 807 * than, equal to, or greater than zero will be returned if the 808 * internal GLX API version is less than, equal to, or greater 809 * than \c required_version. 810 * 811 * \sa __glXGetInternalVersion(). 812 */ 813int driCompareGLXAPIVersion( GLint required_version ) 814{ 815 if ( api_ver > required_version ) { 816 return 1; 817 } 818 else if ( api_ver == required_version ) { 819 return 0; 820 } 821 822 return -1; 823} 824 825 826static int 827driQueryFrameTracking( void * priv, 828 int64_t * sbc, int64_t * missedFrames, 829 float * lastMissedUsage, float * usage ) 830{ 831 __DRIswapInfo sInfo; 832 int status; 833 int64_t ust; 834 __DRIdrawablePrivate * dpriv = (__DRIdrawablePrivate *) priv; 835 836 837 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo ); 838 if ( status == 0 ) { 839 *sbc = sInfo.swap_count; 840 *missedFrames = sInfo.swap_missed_count; 841 *lastMissedUsage = sInfo.swap_missed_usage; 842 843 (*dri_interface->getUST)( & ust ); 844 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust ); 845 } 846 847 return status; 848} 849 850 851/** 852 * Calculate amount of swap interval used between GLX buffer swaps. 853 * 854 * The usage value, on the range [0,max], is the fraction of total swap 855 * interval time used between GLX buffer swaps is calculated. 856 * 857 * \f$p = t_d / (i * t_r)\f$ 858 * 859 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the 860 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time 861 * required for a single vertical refresh period (as returned by \c 862 * glXGetMscRateOML). 863 * 864 * See the documentation for the GLX_MESA_swap_frame_usage extension for more 865 * details. 866 * 867 * \param dPriv Pointer to the private drawable structure. 868 * \return If less than a single swap interval time period was required 869 * between GLX buffer swaps, a number greater than 0 and less than 870 * 1.0 is returned. If exactly one swap interval time period is 871 * required, 1.0 is returned, and if more than one is required then 872 * a number greater than 1.0 will be returned. 873 * 874 * \sa glXSwapIntervalSGI glXGetMscRateOML 875 * 876 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it 877 * be possible to cache the sync rate? 878 */ 879float 880driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust, 881 int64_t current_ust ) 882{ 883 int32_t n; 884 int32_t d; 885 int interval; 886 float usage = 1.0; 887 888 889 if ( (*dri_interface->getMSCRate)(dPriv->pdraw, &n, &d) ) { 890 interval = (dPriv->pdraw->swap_interval != 0) 891 ? dPriv->pdraw->swap_interval : 1; 892 893 894 /* We want to calculate 895 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get 896 * current_UST by calling __glXGetUST. last_swap_UST is stored in 897 * dPriv->swap_ust. interval has already been calculated. 898 * 899 * The only tricky part is us_per_refresh. us_per_refresh is 900 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it 901 * around and say us_per_refresh = 1000000 * d / n. Since this goes in 902 * the denominator of the final calculation, we calculate 903 * (interval * 1000000 * d) and move n into the numerator. 904 */ 905 906 usage = (current_ust - last_swap_ust); 907 usage *= n; 908 usage /= (interval * d); 909 usage /= 1000000.0; 910 } 911 912 return usage; 913} 914 915/*@}*/ 916