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)
33 #include "drm_sarea.h"
35 #ifndef GLX_OML_sync_control
36 typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC
) (__DRIdrawable
*drawable
, int32_t *numerator
, int32_t *denominator
);
39 /* This pointer *must* be set by the driver's __driCreateNewScreen funciton!
41 const __DRIinterfaceMethods
* dri_interface
= NULL
;
44 * This is used in a couple of places that call \c driCreateNewDrawable.
46 static const int empty_attribute_list
[1] = { None
};
50 * Cached copy of the internal API version used by libGL and the client-side
53 static int api_ver
= 0;
55 static void *driCreateNewDrawable(__DRIscreen
*screen
,
56 const __GLcontextModes
*modes
,
58 drm_drawable_t hwDrawable
,
59 int renderType
, const int *attrs
);
61 static void driDestroyDrawable(__DRIdrawable
*drawable
);
65 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
68 * Is called from the drivers.
70 * \param f \c printf like format string.
73 __driUtilMessage(const char *f
, ...)
77 if (getenv("LIBGL_DEBUG")) {
78 fprintf(stderr
, "libGL error: \n");
80 vfprintf(stderr
, f
, args
);
82 fprintf(stderr
, "\n");
87 /*****************************************************************/
88 /** \name Context (un)binding functions */
89 /*****************************************************************/
95 * \param scrn the screen.
98 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
101 * This function calls __DriverAPIRec::UnbindContext, and then decrements
102 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
105 * While casting the opaque private pointers associated with the parameters
106 * into their respective real types it also assures they are not \c NULL.
108 static GLboolean
driUnbindContext(__DRIcontext
*ctx
)
110 __DRIcontextPrivate
*pcp
;
111 __DRIscreenPrivate
*psp
;
112 __DRIdrawablePrivate
*pdp
;
113 __DRIdrawablePrivate
*prp
;
116 ** Assume error checking is done properly in glXMakeCurrent before
117 ** calling driUnbindContext.
123 pcp
= (__DRIcontextPrivate
*)ctx
->private;
124 psp
= (__DRIscreenPrivate
*)pcp
->driScreenPriv
;
125 pdp
= (__DRIdrawablePrivate
*)pcp
->driDrawablePriv
;
126 prp
= (__DRIdrawablePrivate
*)pcp
->driReadablePriv
;
128 /* Let driver unbind drawable from context */
129 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
131 if (pdp
->refcount
== 0) {
139 if (prp
->refcount
== 0) {
148 /* XXX this is disabled so that if we call SwapBuffers on an unbound
149 * window we can determine the last context bound to the window and
150 * use that context's lock. (BrianP, 2-Dec-2000)
153 /* Unbind the drawable */
154 pcp
->driDrawablePriv
= NULL
;
155 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
163 * This function takes both a read buffer and a draw buffer. This is needed
164 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
167 static GLboolean
DoBindContext(__DRIcontext
*ctx
,
168 __DRIdrawable
*pdraw
,
169 __DRIdrawable
*pread
)
171 __DRIdrawablePrivate
*pdp
;
172 __DRIdrawablePrivate
*prp
;
173 __DRIcontextPrivate
* const pcp
= ctx
->private;
174 __DRIscreenPrivate
*psp
= pcp
->driScreenPriv
;
176 pdp
= (__DRIdrawablePrivate
*) pdraw
->private;
177 prp
= (__DRIdrawablePrivate
*) pread
->private;
179 /* Bind the drawable to the context */
180 pcp
->driDrawablePriv
= pdp
;
181 pcp
->driReadablePriv
= prp
;
182 pdp
->driContextPriv
= pcp
;
189 ** Now that we have a context associated with this drawable, we can
190 ** initialize the drawable information if has not been done before.
192 if (!pdp
->pStamp
|| *pdp
->pStamp
!= pdp
->lastStamp
) {
193 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
194 __driUtilUpdateDrawableInfo(pdp
);
195 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
198 if ((pdp
!= prp
) && (!prp
->pStamp
|| *prp
->pStamp
!= prp
->lastStamp
)) {
199 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
200 __driUtilUpdateDrawableInfo(prp
);
201 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
204 /* Call device-specific MakeCurrent */
205 (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, prp
);
212 * This function takes both a read buffer and a draw buffer. This is needed
213 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
216 static GLboolean
driBindContext(__DRIcontext
* ctx
,
217 __DRIdrawable
*pdraw
,
218 __DRIdrawable
*pread
)
221 ** Assume error checking is done properly in glXMakeCurrent before
222 ** calling driBindContext.
225 if (ctx
== NULL
|| pdraw
== None
|| pread
== None
)
228 return DoBindContext( ctx
, pdraw
, pread
);
233 /*****************************************************************/
234 /** \name Drawable handling functions */
235 /*****************************************************************/
239 * Update private drawable information.
241 * \param pdp pointer to the private drawable information to update.
243 * This function basically updates the __DRIdrawablePrivate struct's
244 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
245 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
246 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
247 * the values are different that means we have to update the clipping
251 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate
*pdp
)
253 __DRIscreenPrivate
*psp
;
254 __DRIcontextPrivate
*pcp
= pdp
->driContextPriv
;
257 || ((pdp
!= pcp
->driDrawablePriv
) && (pdp
!= pcp
->driReadablePriv
))) {
259 * ...but we must ignore it. There can be many contexts bound to a
264 psp
= pdp
->driScreenPriv
;
267 _mesa_problem(NULL
, "Warning! Possible infinite loop due to bug "
268 "in file %s, line %d\n",
273 if (pdp
->pClipRects
) {
274 _mesa_free(pdp
->pClipRects
);
275 pdp
->pClipRects
= NULL
;
278 if (pdp
->pBackClipRects
) {
279 _mesa_free(pdp
->pBackClipRects
);
280 pdp
->pBackClipRects
= NULL
;
283 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
285 if (! (*dri_interface
->getDrawableInfo
)(pdp
->pdraw
,
286 &pdp
->index
, &pdp
->lastStamp
,
287 &pdp
->x
, &pdp
->y
, &pdp
->w
, &pdp
->h
,
288 &pdp
->numClipRects
, &pdp
->pClipRects
,
291 &pdp
->numBackClipRects
,
292 &pdp
->pBackClipRects
)) {
293 /* Error -- eg the window may have been destroyed. Keep going
296 pdp
->pStamp
= &pdp
->lastStamp
; /* prevent endless loop */
297 pdp
->numClipRects
= 0;
298 pdp
->pClipRects
= NULL
;
299 pdp
->numBackClipRects
= 0;
300 pdp
->pBackClipRects
= NULL
;
303 pdp
->pStamp
= &(psp
->pSAREA
->drawableTable
[pdp
->index
].stamp
);
305 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
311 /*****************************************************************/
312 /** \name GLX callbacks */
313 /*****************************************************************/
319 * \param drawablePrivate opaque pointer to the per-drawable private info.
322 * This function calls __DRIdrawablePrivate::swapBuffers.
324 * Is called directly from glXSwapBuffers().
326 static void driSwapBuffers(__DRIdrawable
*drawable
)
328 __DRIdrawablePrivate
*dPriv
= drawable
->private;
329 drm_clip_rect_t rect
;
331 dPriv
->swapBuffers(dPriv
);
333 /* Check that we actually have the new damage report method */
334 if (api_ver
< 20070105 || dri_interface
->reportDamage
== NULL
)
337 /* Assume it's affecting the whole drawable for now */
340 rect
.x2
= rect
.x1
+ dPriv
->w
;
341 rect
.y2
= rect
.y1
+ dPriv
->h
;
343 /* Report the damage. Currently, all our drivers draw directly to the
344 * front buffer, so we report the damage there rather than to the backing
347 (*dri_interface
->reportDamage
)(dPriv
->pdraw
, dPriv
->x
, dPriv
->y
,
352 * Called directly from a number of higher-level GLX functions.
354 static int driGetMSC( __DRIscreen
*screen
, int64_t *msc
)
356 __DRIscreenPrivate
*sPriv
= screen
->private;
358 return sPriv
->DriverAPI
.GetMSC( sPriv
, msc
);
361 static int driWaitForMSC(__DRIdrawable
*drawable
, int64_t target_msc
,
362 int64_t divisor
, int64_t remainder
,
363 int64_t * msc
, int64_t * sbc
)
365 __DRIdrawablePrivate
*dPriv
= drawable
->private;
370 status
= dPriv
->driScreenPriv
->DriverAPI
.WaitForMSC( dPriv
, target_msc
,
374 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
375 * is supported but GLX_OML_sync_control is not. Therefore, don't return
376 * an error value if GetSwapInfo() is not implemented.
379 && dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo
) {
380 status
= dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dPriv
, & sInfo
);
381 *sbc
= sInfo
.swap_count
;
387 const __DRImediaStreamCounterExtension driMediaStreamCounterExtension
= {
388 { __DRI_MEDIA_STREAM_COUNTER
},
393 static void driCopySubBuffer(__DRIdrawable
*drawable
,
394 int x
, int y
, int w
, int h
)
396 __DRIdrawablePrivate
*dPriv
= drawable
->private;
397 dPriv
->driScreenPriv
->DriverAPI
.CopySubBuffer(dPriv
, x
, y
, w
, h
);
400 const __DRIcopySubBufferExtension driCopySubBufferExtension
= {
401 { __DRI_COPY_SUB_BUFFER
}, driCopySubBuffer
404 static void driSetSwapInterval(__DRIdrawable
*drawable
, unsigned int interval
)
406 __DRIdrawablePrivate
*dpriv
= drawable
->private;
408 dpriv
->swap_interval
= interval
;
411 static unsigned int driGetSwapInterval(__DRIdrawable
*drawable
)
413 __DRIdrawablePrivate
*dpriv
= drawable
->private;
415 return dpriv
->swap_interval
;
418 const __DRIswapControlExtension driSwapControlExtension
= {
419 { __DRI_SWAP_CONTROL
},
426 * This is called via __DRIscreenRec's createNewDrawable pointer.
428 static void *driCreateNewDrawable(__DRIscreen
*screen
,
429 const __GLcontextModes
*modes
,
430 __DRIdrawable
*pdraw
,
431 drm_drawable_t hwDrawable
,
435 __DRIscreenPrivate
*psp
;
436 __DRIdrawablePrivate
*pdp
;
439 pdraw
->private = NULL
;
441 /* Since pbuffers are not yet supported, no drawable attributes are
446 pdp
= (__DRIdrawablePrivate
*)_mesa_malloc(sizeof(__DRIdrawablePrivate
));
451 pdp
->hHWDrawable
= hwDrawable
;
461 pdp
->numClipRects
= 0;
462 pdp
->numBackClipRects
= 0;
463 pdp
->pClipRects
= NULL
;
464 pdp
->pBackClipRects
= NULL
;
466 psp
= (__DRIscreenPrivate
*)screen
->private;
467 pdp
->driScreenPriv
= psp
;
468 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
470 if (!(*psp
->DriverAPI
.CreateBuffer
)(psp
, pdp
, modes
,
471 renderType
== GLX_PIXMAP_BIT
)) {
476 pdraw
->private = pdp
;
477 pdraw
->destroyDrawable
= driDestroyDrawable
;
478 pdraw
->swapBuffers
= driSwapBuffers
; /* called by glXSwapBuffers() */
480 /* This special default value is replaced with the configured
481 * default value when the drawable is first bound to a direct
484 pdp
->swap_interval
= (unsigned)-1;
486 pdp
->swapBuffers
= psp
->DriverAPI
.SwapBuffers
;
492 driDestroyDrawable(__DRIdrawable
*drawable
)
494 __DRIdrawablePrivate
*pdp
= drawable
->private;
495 __DRIscreenPrivate
*psp
;
498 psp
= pdp
->driScreenPriv
;
499 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
500 if (pdp
->pClipRects
) {
501 _mesa_free(pdp
->pClipRects
);
502 pdp
->pClipRects
= NULL
;
504 if (pdp
->pBackClipRects
) {
505 _mesa_free(pdp
->pBackClipRects
);
506 pdp
->pBackClipRects
= NULL
;
515 /*****************************************************************/
516 /** \name Context handling functions */
517 /*****************************************************************/
521 * Destroy the per-context private information.
523 * \param contextPrivate opaque pointer to the per-drawable private info.
526 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
527 * drmDestroyContext(), and finally frees \p contextPrivate.
530 driDestroyContext(__DRIcontext
*context
)
532 __DRIcontextPrivate
*pcp
= context
->private;
535 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
542 * Create the per-drawable private driver information.
544 * \param dpy The display handle.
545 * \param modes Mode used to create the new context.
546 * \param render_type Type of rendering target. \c GLX_RGBA is the only
547 * type likely to ever be supported for direct-rendering.
548 * \param sharedPrivate The shared context dependent methods or \c NULL if
550 * \param pctx DRI context to receive the context dependent methods.
552 * \returns An opaque pointer to the per-context private information on
553 * success, or \c NULL on failure.
556 * This function allocates and fills a __DRIcontextPrivateRec structure. It
557 * performs some device independent initialization and passes all the
558 * relevent information to __DriverAPIRec::CreateContext to create the
563 driCreateNewContext(__DRIscreen
*screen
, const __GLcontextModes
*modes
,
564 int render_type
, void *sharedPrivate
,
565 drm_context_t hwContext
, __DRIcontext
*pctx
)
567 __DRIcontextPrivate
*pcp
;
568 __DRIcontextPrivate
*pshare
= (__DRIcontextPrivate
*) sharedPrivate
;
569 __DRIscreenPrivate
*psp
;
570 void * const shareCtx
= (pshare
!= NULL
) ? pshare
->driverPrivate
: NULL
;
572 psp
= (__DRIscreenPrivate
*)screen
->private;
574 pcp
= (__DRIcontextPrivate
*)_mesa_malloc(sizeof(__DRIcontextPrivate
));
579 pcp
->hHWContext
= hwContext
;
580 pcp
->driScreenPriv
= psp
;
581 pcp
->driDrawablePriv
= NULL
;
583 /* When the first context is created for a screen, initialize a "dummy"
587 if (!psp
->dummyContextPriv
.driScreenPriv
) {
588 psp
->dummyContextPriv
.hHWContext
= psp
->pSAREA
->dummy_context
;
589 psp
->dummyContextPriv
.driScreenPriv
= psp
;
590 psp
->dummyContextPriv
.driDrawablePriv
= NULL
;
591 psp
->dummyContextPriv
.driverPrivate
= NULL
;
592 /* No other fields should be used! */
595 pctx
->destroyContext
= driDestroyContext
;
596 pctx
->bindContext
= driBindContext
;
597 pctx
->unbindContext
= driUnbindContext
;
599 if ( !(*psp
->DriverAPI
.CreateContext
)(modes
, pcp
, shareCtx
) ) {
609 static const __DRIextension
**
610 driGetExtensions(__DRIscreen
*screen
)
612 __DRIscreenPrivate
*psp
= screen
->private;
614 return psp
->extensions
;
617 /*****************************************************************/
618 /** \name Screen handling functions */
619 /*****************************************************************/
623 * Destroy the per-screen private information.
625 * \param dpy the display handle.
626 * \param scrn the screen number.
627 * \param screenPrivate opaque pointer to the per-screen private information.
630 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
631 * drmClose(), and finally frees \p screenPrivate.
633 static void driDestroyScreen(__DRIscreen
*screen
)
635 __DRIscreenPrivate
*psp
= screen
->private;
638 /* No interaction with the X-server is possible at this point. This
639 * routine is called after XCloseDisplay, so there is no protocol
640 * stream open to the X-server anymore.
643 if (psp
->DriverAPI
.DestroyScreen
)
644 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
646 (void)drmUnmap((drmAddress
)psp
->pSAREA
, SAREA_MAX
);
647 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
648 (void)drmCloseOnce(psp
->fd
);
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
662 * \param scrn Index of the screen
663 * \param psc DRI screen data (not driver private)
664 * \param modes Linked list of known display modes. This list is, at a
665 * minimum, a list of modes based on the current display mode.
666 * These roughly match the set of available X11 visuals, but it
667 * need not be limited to X11! The calling libGL should create
668 * a list that will inform the driver of the current display
669 * mode (i.e., color buffer depth, depth buffer depth, etc.).
670 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
672 * \param dri_version Version of the "server-side" DRI.
673 * \param drm_version Version of the kernel DRM.
674 * \param frame_buffer Data describing the location and layout of the
676 * \param pSAREA Pointer the the SAREA.
677 * \param fd Device handle for the DRM.
678 * \param internal_api_version Version of the internal interface between the
680 * \param driverAPI Driver API functions used by other routines in dri_util.c.
682 * \note There is no need to check the minimum API version in this
683 * function. Since the name of this function is versioned, it is
684 * impossible for a loader that is too old to even load this driver.
687 void * __DRI_CREATE_NEW_SCREEN( int scrn
, __DRIscreen
*psc
,
688 const __DRIversion
* ddx_version
,
689 const __DRIversion
* dri_version
,
690 const __DRIversion
* drm_version
,
691 const __DRIframebuffer
* frame_buffer
,
692 drmAddress pSAREA
, int fd
,
693 int internal_api_version
,
694 const __DRIinterfaceMethods
* interface
,
695 __GLcontextModes
** driver_modes
)
698 __DRIscreenPrivate
*psp
;
699 static const __DRIextension
*emptyExtensionList
[] = { NULL
};
700 dri_interface
= interface
;
701 api_ver
= internal_api_version
;
703 psp
= _mesa_malloc(sizeof(*psp
));
710 ** NOT_DONE: This is used by the X server to detect when the client
711 ** has died while holding the drawable lock. The client sets the
712 ** drawable lock to this value.
716 psp
->drm_version
= *drm_version
;
717 psp
->ddx_version
= *ddx_version
;
718 psp
->dri_version
= *dri_version
;
720 psp
->pSAREA
= pSAREA
;
722 psp
->pFB
= frame_buffer
->base
;
723 psp
->fbSize
= frame_buffer
->size
;
724 psp
->fbStride
= frame_buffer
->stride
;
725 psp
->fbWidth
= frame_buffer
->width
;
726 psp
->fbHeight
= frame_buffer
->height
;
727 psp
->devPrivSize
= frame_buffer
->dev_priv_size
;
728 psp
->pDevPriv
= frame_buffer
->dev_priv
;
729 psp
->fbBPP
= psp
->fbStride
* 8 / frame_buffer
->width
;
731 psp
->extensions
= emptyExtensionList
;
736 ** Do not init dummy context here; actual initialization will be
737 ** done when the first DRI context is created. Init screen priv ptr
738 ** to NULL to let CreateContext routine that it needs to be inited.
740 psp
->dummyContextPriv
.driScreenPriv
= NULL
;
742 psc
->destroyScreen
= driDestroyScreen
;
743 psc
->getExtensions
= driGetExtensions
;
744 psc
->createNewDrawable
= driCreateNewDrawable
;
745 psc
->createNewContext
= driCreateNewContext
;
747 if (internal_api_version
>= 20070121)
748 psc
->setTexOffset
= psp
->DriverAPI
.setTexOffset
;
750 *driver_modes
= __driDriverInitScreen(psp
);
751 if (*driver_modes
== NULL
) {
760 * Compare the current GLX API version with a driver supplied required version.
762 * The minimum required version is compared with the API version exported by
763 * the \c __glXGetInternalVersion function (in libGL.so).
765 * \param required_version Minimum required internal GLX API version.
766 * \return A tri-value return, as from strcmp is returned. A value less
767 * than, equal to, or greater than zero will be returned if the
768 * internal GLX API version is less than, equal to, or greater
769 * than \c required_version.
771 * \sa __glXGetInternalVersion().
773 int driCompareGLXAPIVersion( GLint required_version
)
775 if ( api_ver
> required_version
) {
778 else if ( api_ver
== required_version
) {
787 driFrameTracking(__DRIdrawable
*drawable
, GLboolean enable
)
789 return GLX_BAD_CONTEXT
;
793 driQueryFrameTracking(__DRIdrawable
*drawable
,
794 int64_t * sbc
, int64_t * missedFrames
,
795 float * lastMissedUsage
, float * usage
)
800 __DRIdrawablePrivate
* dpriv
= drawable
->private;
803 status
= dpriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dpriv
, & sInfo
);
805 *sbc
= sInfo
.swap_count
;
806 *missedFrames
= sInfo
.swap_missed_count
;
807 *lastMissedUsage
= sInfo
.swap_missed_usage
;
809 (*dri_interface
->getUST
)( & ust
);
810 *usage
= driCalculateSwapUsage( dpriv
, sInfo
.swap_ust
, ust
);
816 const __DRIframeTrackingExtension driFrameTrackingExtension
= {
817 { __DRI_FRAME_TRACKING
},
819 driQueryFrameTracking
823 * Calculate amount of swap interval used between GLX buffer swaps.
825 * The usage value, on the range [0,max], is the fraction of total swap
826 * interval time used between GLX buffer swaps is calculated.
828 * \f$p = t_d / (i * t_r)\f$
830 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
831 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
832 * required for a single vertical refresh period (as returned by \c
835 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
838 * \param dPriv Pointer to the private drawable structure.
839 * \return If less than a single swap interval time period was required
840 * between GLX buffer swaps, a number greater than 0 and less than
841 * 1.0 is returned. If exactly one swap interval time period is
842 * required, 1.0 is returned, and if more than one is required then
843 * a number greater than 1.0 will be returned.
845 * \sa glXSwapIntervalSGI glXGetMscRateOML
847 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
848 * be possible to cache the sync rate?
851 driCalculateSwapUsage( __DRIdrawablePrivate
*dPriv
, int64_t last_swap_ust
,
852 int64_t current_ust
)
860 if ( (*dri_interface
->getMSCRate
)(dPriv
->pdraw
, &n
, &d
) ) {
861 interval
= (dPriv
->swap_interval
!= 0) ? dPriv
->swap_interval
: 1;
864 /* We want to calculate
865 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
866 * current_UST by calling __glXGetUST. last_swap_UST is stored in
867 * dPriv->swap_ust. interval has already been calculated.
869 * The only tricky part is us_per_refresh. us_per_refresh is
870 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
871 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
872 * the denominator of the final calculation, we calculate
873 * (interval * 1000000 * d) and move n into the numerator.
876 usage
= (current_ust
- last_swap_ust
);
878 usage
/= (interval
* d
);