1 /* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */
4 * DRI utility functions.
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
11 * Basically, these utility functions take care of some of the dirty details of
12 * screen initialization, context creation, context binding, DRM setup, etc.
14 * These functions are compiled into each DRI driver so libGL.so knows nothing
26 #define MAP_FAILED ((void *)-1)
29 #include "main/imports.h"
33 #include "drm_sarea.h"
36 #ifndef GLX_OML_sync_control
37 typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC
) (__DRIdrawable
*drawable
, int32_t *numerator
, int32_t *denominator
);
41 * This is just a token extension used to signal that the driver
42 * supports setting a read drawable.
44 const __DRIextension driReadDrawableExtension
= {
45 __DRI_READ_DRAWABLE
, __DRI_READ_DRAWABLE_VERSION
49 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
52 * Is called from the drivers.
54 * \param f \c printf like format string.
57 __driUtilMessage(const char *f
, ...)
61 if (getenv("LIBGL_DEBUG")) {
62 fprintf(stderr
, "libGL: ");
64 vfprintf(stderr
, f
, args
);
66 fprintf(stderr
, "\n");
71 driIntersectArea( drm_clip_rect_t rect1
, drm_clip_rect_t rect2
)
73 if (rect2
.x1
> rect1
.x1
) rect1
.x1
= rect2
.x1
;
74 if (rect2
.x2
< rect1
.x2
) rect1
.x2
= rect2
.x2
;
75 if (rect2
.y1
> rect1
.y1
) rect1
.y1
= rect2
.y1
;
76 if (rect2
.y2
< rect1
.y2
) rect1
.y2
= rect2
.y2
;
78 if (rect1
.x1
> rect1
.x2
|| rect1
.y1
> rect1
.y2
) return 0;
80 return (rect1
.x2
- rect1
.x1
) * (rect1
.y2
- rect1
.y1
);
83 /*****************************************************************/
84 /** \name Context (un)binding functions */
85 /*****************************************************************/
91 * \param scrn the screen.
94 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
97 * This function calls __DriverAPIRec::UnbindContext, and then decrements
98 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
101 * While casting the opaque private pointers associated with the parameters
102 * into their respective real types it also assures they are not \c NULL.
104 static int driUnbindContext(__DRIcontext
*pcp
)
111 ** Assume error checking is done properly in glXMakeCurrent before
112 ** calling driUnbindContext.
118 psp
= pcp
->driScreenPriv
;
119 pdp
= pcp
->driDrawablePriv
;
120 prp
= pcp
->driReadablePriv
;
122 /* Let driver unbind drawable from context */
123 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
125 if (pdp
->refcount
== 0) {
133 if (prp
->refcount
== 0) {
142 /* XXX this is disabled so that if we call SwapBuffers on an unbound
143 * window we can determine the last context bound to the window and
144 * use that context's lock. (BrianP, 2-Dec-2000)
147 /* Unbind the drawable */
148 pcp
->driDrawablePriv
= NULL
;
149 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
156 * This function takes both a read buffer and a draw buffer. This is needed
157 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
160 static int driBindContext(__DRIcontext
*pcp
,
164 __DRIscreenPrivate
*psp
= pcp
->driScreenPriv
;
166 /* Bind the drawable to the context */
169 pcp
->driDrawablePriv
= pdp
;
170 pcp
->driReadablePriv
= prp
;
172 pdp
->driContextPriv
= pcp
;
175 if ( prp
&& pdp
!= prp
) {
181 ** Now that we have a context associated with this drawable, we can
182 ** initialize the drawable information if has not been done before.
185 if (!psp
->dri2
.enabled
) {
186 if (pdp
&& !pdp
->pStamp
) {
187 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
188 __driUtilUpdateDrawableInfo(pdp
);
189 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
191 if (prp
&& pdp
!= prp
&& !prp
->pStamp
) {
192 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
193 __driUtilUpdateDrawableInfo(prp
);
194 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
198 /* Call device-specific MakeCurrent */
200 return (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, prp
);
206 /*****************************************************************/
207 /** \name Drawable handling functions */
208 /*****************************************************************/
212 * Update private drawable information.
214 * \param pdp pointer to the private drawable information to update.
216 * This function basically updates the __DRIdrawablePrivate struct's
217 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
218 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
219 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
220 * the values are different that means we have to update the clipping
224 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate
*pdp
)
226 __DRIscreenPrivate
*psp
= pdp
->driScreenPriv
;
227 __DRIcontextPrivate
*pcp
= pdp
->driContextPriv
;
230 || ((pdp
!= pcp
->driDrawablePriv
) && (pdp
!= pcp
->driReadablePriv
))) {
232 * ...but we must ignore it. There can be many contexts bound to a
237 if (pdp
->pClipRects
) {
238 _mesa_free(pdp
->pClipRects
);
239 pdp
->pClipRects
= NULL
;
242 if (pdp
->pBackClipRects
) {
243 _mesa_free(pdp
->pBackClipRects
);
244 pdp
->pBackClipRects
= NULL
;
247 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
249 if (! (*psp
->getDrawableInfo
->getDrawableInfo
)(pdp
,
250 &pdp
->index
, &pdp
->lastStamp
,
251 &pdp
->x
, &pdp
->y
, &pdp
->w
, &pdp
->h
,
252 &pdp
->numClipRects
, &pdp
->pClipRects
,
255 &pdp
->numBackClipRects
,
256 &pdp
->pBackClipRects
,
257 pdp
->loaderPrivate
)) {
258 /* Error -- eg the window may have been destroyed. Keep going
261 pdp
->pStamp
= &pdp
->lastStamp
; /* prevent endless loop */
262 pdp
->numClipRects
= 0;
263 pdp
->pClipRects
= NULL
;
264 pdp
->numBackClipRects
= 0;
265 pdp
->pBackClipRects
= NULL
;
268 pdp
->pStamp
= &(psp
->pSAREA
->drawableTable
[pdp
->index
].stamp
);
270 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
275 /*****************************************************************/
276 /** \name GLX callbacks */
277 /*****************************************************************/
280 static void driReportDamage(__DRIdrawable
*pdp
,
281 struct drm_clip_rect
*pClipRects
, int numClipRects
)
283 __DRIscreen
*psp
= pdp
->driScreenPriv
;
285 /* Check that we actually have the new damage report method */
287 /* Report the damage. Currently, all our drivers draw
288 * directly to the front buffer, so we report the damage there
289 * rather than to the backing storein (if any).
291 (*psp
->damage
->reportDamage
)(pdp
,
293 pClipRects
, numClipRects
,
294 GL_TRUE
, pdp
->loaderPrivate
);
302 * \param drawablePrivate opaque pointer to the per-drawable private info.
305 * This function calls __DRIdrawablePrivate::swapBuffers.
307 * Is called directly from glXSwapBuffers().
309 static void driSwapBuffers(__DRIdrawable
*dPriv
)
311 __DRIscreen
*psp
= dPriv
->driScreenPriv
;
312 drm_clip_rect_t
*rects
;
315 psp
->DriverAPI
.SwapBuffers(dPriv
);
317 if (!dPriv
->numClipRects
)
320 rects
= _mesa_malloc(sizeof(*rects
) * dPriv
->numClipRects
);
325 for (i
= 0; i
< dPriv
->numClipRects
; i
++) {
326 rects
[i
].x1
= dPriv
->pClipRects
[i
].x1
- dPriv
->x
;
327 rects
[i
].y1
= dPriv
->pClipRects
[i
].y1
- dPriv
->y
;
328 rects
[i
].x2
= dPriv
->pClipRects
[i
].x2
- dPriv
->x
;
329 rects
[i
].y2
= dPriv
->pClipRects
[i
].y2
- dPriv
->y
;
332 driReportDamage(dPriv
, rects
, dPriv
->numClipRects
);
336 static int driDrawableGetMSC( __DRIscreen
*sPriv
, __DRIdrawable
*dPriv
,
339 return sPriv
->DriverAPI
.GetDrawableMSC(sPriv
, dPriv
, msc
);
343 static int driWaitForMSC(__DRIdrawable
*dPriv
, int64_t target_msc
,
344 int64_t divisor
, int64_t remainder
,
345 int64_t * msc
, int64_t * sbc
)
350 status
= dPriv
->driScreenPriv
->DriverAPI
.WaitForMSC( dPriv
, target_msc
,
354 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
355 * is supported but GLX_OML_sync_control is not. Therefore, don't return
356 * an error value if GetSwapInfo() is not implemented.
359 && dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo
) {
360 status
= dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dPriv
, & sInfo
);
361 *sbc
= sInfo
.swap_count
;
368 const __DRImediaStreamCounterExtension driMediaStreamCounterExtension
= {
369 { __DRI_MEDIA_STREAM_COUNTER
, __DRI_MEDIA_STREAM_COUNTER_VERSION
},
375 static void driCopySubBuffer(__DRIdrawable
*dPriv
,
376 int x
, int y
, int w
, int h
)
378 drm_clip_rect_t rect
;
381 rect
.y1
= dPriv
->h
- y
- h
;
383 rect
.y2
= rect
.y1
+ h
;
384 driReportDamage(dPriv
, &rect
, 1);
386 dPriv
->driScreenPriv
->DriverAPI
.CopySubBuffer(dPriv
, x
, y
, w
, h
);
389 const __DRIcopySubBufferExtension driCopySubBufferExtension
= {
390 { __DRI_COPY_SUB_BUFFER
, __DRI_COPY_SUB_BUFFER_VERSION
},
394 static void driSetSwapInterval(__DRIdrawable
*dPriv
, unsigned int interval
)
396 dPriv
->swap_interval
= interval
;
399 static unsigned int driGetSwapInterval(__DRIdrawable
*dPriv
)
401 return dPriv
->swap_interval
;
404 const __DRIswapControlExtension driSwapControlExtension
= {
405 { __DRI_SWAP_CONTROL
, __DRI_SWAP_CONTROL_VERSION
},
412 * This is called via __DRIscreenRec's createNewDrawable pointer.
414 static __DRIdrawable
*
415 driCreateNewDrawable(__DRIscreen
*psp
, const __DRIconfig
*config
,
416 drm_drawable_t hwDrawable
, int renderType
,
417 const int *attrs
, void *data
)
421 /* Since pbuffers are not yet supported, no drawable attributes are
426 pdp
= _mesa_malloc(sizeof *pdp
);
431 pdp
->loaderPrivate
= data
;
432 pdp
->hHWDrawable
= hwDrawable
;
441 pdp
->numClipRects
= 0;
442 pdp
->numBackClipRects
= 0;
443 pdp
->pClipRects
= NULL
;
444 pdp
->pBackClipRects
= NULL
;
448 pdp
->driScreenPriv
= psp
;
449 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
451 if (!(*psp
->DriverAPI
.CreateBuffer
)(psp
, pdp
, &config
->modes
,
452 renderType
== GLX_PIXMAP_BIT
)) {
459 /* This special default value is replaced with the configured
460 * default value when the drawable is first bound to a direct
463 pdp
->swap_interval
= (unsigned)-1;
469 static __DRIdrawable
*
470 dri2CreateNewDrawable(__DRIscreen
*screen
,
471 const __DRIconfig
*config
,
474 __DRIdrawable
*pdraw
;
476 pdraw
= driCreateNewDrawable(screen
, config
, 0, 0, NULL
, loaderPrivate
);
480 pdraw
->pClipRects
= _mesa_malloc(sizeof *pdraw
->pBackClipRects
);
481 pdraw
->pBackClipRects
= _mesa_malloc(sizeof *pdraw
->pBackClipRects
);
488 driDestroyDrawable(__DRIdrawable
*pdp
)
490 __DRIscreenPrivate
*psp
;
493 psp
= pdp
->driScreenPriv
;
494 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
495 if (pdp
->pClipRects
) {
496 _mesa_free(pdp
->pClipRects
);
497 pdp
->pClipRects
= NULL
;
499 if (pdp
->pBackClipRects
) {
500 _mesa_free(pdp
->pBackClipRects
);
501 pdp
->pBackClipRects
= NULL
;
510 /*****************************************************************/
511 /** \name Context handling functions */
512 /*****************************************************************/
516 * Destroy the per-context private information.
519 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
520 * drmDestroyContext(), and finally frees \p contextPrivate.
523 driDestroyContext(__DRIcontext
*pcp
)
526 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
533 * Create the per-drawable private driver information.
535 * \param render_type Type of rendering target. \c GLX_RGBA is the only
536 * type likely to ever be supported for direct-rendering.
537 * \param shared Context with which to share textures, etc. or NULL
539 * \returns An opaque pointer to the per-context private information on
540 * success, or \c NULL on failure.
543 * This function allocates and fills a __DRIcontextPrivateRec structure. It
544 * performs some device independent initialization and passes all the
545 * relevent information to __DriverAPIRec::CreateContext to create the
549 static __DRIcontext
*
550 driCreateNewContext(__DRIscreen
*psp
, const __DRIconfig
*config
,
551 int render_type
, __DRIcontext
*shared
,
552 drm_context_t hwContext
, void *data
)
555 void * const shareCtx
= (shared
!= NULL
) ? shared
->driverPrivate
: NULL
;
557 pcp
= _mesa_malloc(sizeof *pcp
);
561 pcp
->driScreenPriv
= psp
;
562 pcp
->driDrawablePriv
= NULL
;
564 /* When the first context is created for a screen, initialize a "dummy"
568 if (!psp
->dri2
.enabled
&& !psp
->dummyContextPriv
.driScreenPriv
) {
569 psp
->dummyContextPriv
.hHWContext
= psp
->pSAREA
->dummy_context
;
570 psp
->dummyContextPriv
.driScreenPriv
= psp
;
571 psp
->dummyContextPriv
.driDrawablePriv
= NULL
;
572 psp
->dummyContextPriv
.driverPrivate
= NULL
;
573 /* No other fields should be used! */
576 pcp
->hHWContext
= hwContext
;
578 if ( !(*psp
->DriverAPI
.CreateContext
)(&config
->modes
, pcp
, shareCtx
) ) {
587 static __DRIcontext
*
588 dri2CreateNewContext(__DRIscreen
*screen
, const __DRIconfig
*config
,
589 __DRIcontext
*shared
, void *data
)
591 return driCreateNewContext(screen
, config
, 0, shared
, 0, data
);
596 driCopyContext(__DRIcontext
*dest
, __DRIcontext
*src
, unsigned long mask
)
604 /*****************************************************************/
605 /** \name Screen handling functions */
606 /*****************************************************************/
610 * Destroy the per-screen private information.
613 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
614 * drmClose(), and finally frees \p screenPrivate.
616 static void driDestroyScreen(__DRIscreen
*psp
)
619 /* No interaction with the X-server is possible at this point. This
620 * routine is called after XCloseDisplay, so there is no protocol
621 * stream open to the X-server anymore.
624 if (psp
->DriverAPI
.DestroyScreen
)
625 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
627 if (!psp
->dri2
.enabled
) {
628 (void)drmUnmap((drmAddress
)psp
->pSAREA
, SAREA_MAX
);
629 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
630 (void)drmCloseOnce(psp
->fd
);
638 setupLoaderExtensions(__DRIscreen
*psp
,
639 const __DRIextension
**extensions
)
643 for (i
= 0; extensions
[i
]; i
++) {
644 if (strcmp(extensions
[i
]->name
, __DRI_GET_DRAWABLE_INFO
) == 0)
645 psp
->getDrawableInfo
= (__DRIgetDrawableInfoExtension
*) extensions
[i
];
646 if (strcmp(extensions
[i
]->name
, __DRI_DAMAGE
) == 0)
647 psp
->damage
= (__DRIdamageExtension
*) extensions
[i
];
648 if (strcmp(extensions
[i
]->name
, __DRI_SYSTEM_TIME
) == 0)
649 psp
->systemTime
= (__DRIsystemTimeExtension
*) extensions
[i
];
650 if (strcmp(extensions
[i
]->name
, __DRI_DRI2_LOADER
) == 0)
651 psp
->dri2
.loader
= (__DRIdri2LoaderExtension
*) extensions
[i
];
656 * This is the bootstrap function for the driver. libGL supplies all of the
657 * requisite information about the system, and the driver initializes itself.
658 * This routine also fills in the linked list pointed to by \c driver_modes
659 * with the \c __GLcontextModes that the driver can support for windows or
664 * \param scrn Index of the screen
665 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
667 * \param dri_version Version of the "server-side" DRI.
668 * \param drm_version Version of the kernel DRM.
669 * \param frame_buffer Data describing the location and layout of the
671 * \param pSAREA Pointer the the SAREA.
672 * \param fd Device handle for the DRM.
673 * \param extensions ??
674 * \param driver_modes Returns modes suppoted by the driver
675 * \param loaderPrivate ??
677 * \note There is no need to check the minimum API version in this
678 * function. Since the name of this function is versioned, it is
679 * impossible for a loader that is too old to even load this driver.
682 driCreateNewScreen(int scrn
,
683 const __DRIversion
*ddx_version
,
684 const __DRIversion
*dri_version
,
685 const __DRIversion
*drm_version
,
686 const __DRIframebuffer
*frame_buffer
,
687 drmAddress pSAREA
, int fd
,
688 const __DRIextension
**extensions
,
689 const __DRIconfig
***driver_modes
,
692 static const __DRIextension
*emptyExtensionList
[] = { NULL
};
695 psp
= _mesa_calloc(sizeof *psp
);
699 setupLoaderExtensions(psp
, extensions
);
702 ** NOT_DONE: This is used by the X server to detect when the client
703 ** has died while holding the drawable lock. The client sets the
704 ** drawable lock to this value.
708 psp
->drm_version
= *drm_version
;
709 psp
->ddx_version
= *ddx_version
;
710 psp
->dri_version
= *dri_version
;
712 psp
->pSAREA
= pSAREA
;
713 psp
->lock
= (drmLock
*) &psp
->pSAREA
->lock
;
715 psp
->pFB
= frame_buffer
->base
;
716 psp
->fbSize
= frame_buffer
->size
;
717 psp
->fbStride
= frame_buffer
->stride
;
718 psp
->fbWidth
= frame_buffer
->width
;
719 psp
->fbHeight
= frame_buffer
->height
;
720 psp
->devPrivSize
= frame_buffer
->dev_priv_size
;
721 psp
->pDevPriv
= frame_buffer
->dev_priv
;
722 psp
->fbBPP
= psp
->fbStride
* 8 / frame_buffer
->width
;
724 psp
->extensions
= emptyExtensionList
;
727 psp
->dri2
.enabled
= GL_FALSE
;
730 ** Do not init dummy context here; actual initialization will be
731 ** done when the first DRI context is created. Init screen priv ptr
732 ** to NULL to let CreateContext routine that it needs to be inited.
734 psp
->dummyContextPriv
.driScreenPriv
= NULL
;
736 psp
->DriverAPI
= driDriverAPI
;
738 *driver_modes
= driDriverAPI
.InitScreen(psp
);
739 if (*driver_modes
== NULL
) {
751 dri2CreateNewScreen(int scrn
, int fd
,
752 const __DRIextension
**extensions
,
753 const __DRIconfig
***driver_configs
, void *data
)
755 static const __DRIextension
*emptyExtensionList
[] = { NULL
};
757 drmVersionPtr version
;
759 if (driDriverAPI
.InitScreen2
== NULL
)
762 psp
= _mesa_malloc(sizeof(*psp
));
766 setupLoaderExtensions(psp
, extensions
);
768 version
= drmGetVersion(fd
);
770 psp
->drm_version
.major
= version
->version_major
;
771 psp
->drm_version
.minor
= version
->version_minor
;
772 psp
->drm_version
.patch
= version
->version_patchlevel
;
773 drmFreeVersion(version
);
776 psp
->extensions
= emptyExtensionList
;
779 psp
->dri2
.enabled
= GL_TRUE
;
781 psp
->DriverAPI
= driDriverAPI
;
782 *driver_configs
= driDriverAPI
.InitScreen2(psp
);
783 if (*driver_configs
== NULL
) {
788 psp
->DriverAPI
= driDriverAPI
;
793 static const __DRIextension
**driGetExtensions(__DRIscreen
*psp
)
795 return psp
->extensions
;
798 /** Core interface */
799 const __DRIcoreExtension driCoreExtension
= {
800 { __DRI_CORE
, __DRI_CORE_VERSION
},
805 driIndexConfigAttrib
,
816 /** Legacy DRI interface */
817 const __DRIlegacyExtension driLegacyExtension
= {
818 { __DRI_LEGACY
, __DRI_LEGACY_VERSION
},
820 driCreateNewDrawable
,
824 /** Legacy DRI interface */
825 const __DRIdri2Extension driDRI2Extension
= {
826 { __DRI_DRI2
, __DRI_DRI2_VERSION
},
828 dri2CreateNewDrawable
,
829 dri2CreateNewContext
,
832 /* This is the table of extensions that the loader will dlsym() for. */
833 PUBLIC
const __DRIextension
*__driDriverExtensions
[] = {
834 &driCoreExtension
.base
,
835 &driLegacyExtension
.base
,
836 &driDRI2Extension
.base
,
841 driFrameTracking(__DRIdrawable
*drawable
, GLboolean enable
)
843 return GLX_BAD_CONTEXT
;
847 driQueryFrameTracking(__DRIdrawable
*dpriv
,
848 int64_t * sbc
, int64_t * missedFrames
,
849 float * lastMissedUsage
, float * usage
)
854 __DRIscreenPrivate
*psp
= dpriv
->driScreenPriv
;
856 status
= dpriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dpriv
, & sInfo
);
858 *sbc
= sInfo
.swap_count
;
859 *missedFrames
= sInfo
.swap_missed_count
;
860 *lastMissedUsage
= sInfo
.swap_missed_usage
;
862 (*psp
->systemTime
->getUST
)( & ust
);
863 *usage
= driCalculateSwapUsage( dpriv
, sInfo
.swap_ust
, ust
);
869 const __DRIframeTrackingExtension driFrameTrackingExtension
= {
870 { __DRI_FRAME_TRACKING
, __DRI_FRAME_TRACKING_VERSION
},
872 driQueryFrameTracking
876 * Calculate amount of swap interval used between GLX buffer swaps.
878 * The usage value, on the range [0,max], is the fraction of total swap
879 * interval time used between GLX buffer swaps is calculated.
881 * \f$p = t_d / (i * t_r)\f$
883 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
884 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
885 * required for a single vertical refresh period (as returned by \c
888 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
891 * \param dPriv Pointer to the private drawable structure.
892 * \return If less than a single swap interval time period was required
893 * between GLX buffer swaps, a number greater than 0 and less than
894 * 1.0 is returned. If exactly one swap interval time period is
895 * required, 1.0 is returned, and if more than one is required then
896 * a number greater than 1.0 will be returned.
898 * \sa glXSwapIntervalSGI glXGetMscRateOML
900 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
901 * be possible to cache the sync rate?
904 driCalculateSwapUsage( __DRIdrawablePrivate
*dPriv
, int64_t last_swap_ust
,
905 int64_t current_ust
)
911 __DRIscreenPrivate
*psp
= dPriv
->driScreenPriv
;
913 if ( (*psp
->systemTime
->getMSCRate
)(dPriv
, &n
, &d
, dPriv
->loaderPrivate
) ) {
914 interval
= (dPriv
->swap_interval
!= 0) ? dPriv
->swap_interval
: 1;
917 /* We want to calculate
918 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
919 * current_UST by calling __glXGetUST. last_swap_UST is stored in
920 * dPriv->swap_ust. interval has already been calculated.
922 * The only tricky part is us_per_refresh. us_per_refresh is
923 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
924 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
925 * the denominator of the final calculation, we calculate
926 * (interval * 1000000 * d) and move n into the numerator.
929 usage
= (current_ust
- last_swap_ust
);
931 usage
/= (interval
* d
);