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