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 /* forward declarations */
56 static int driQueryFrameTracking( __DRIdrawable
*drawable
,
57 int64_t *sbc
, int64_t *missedFrames
,
58 float *lastMissedUsage
, float *usage
);
60 static void *driCreateNewDrawable(__DRIscreen
*screen
,
61 const __GLcontextModes
*modes
,
63 drm_drawable_t hwDrawable
,
64 int renderType
, const int *attrs
);
66 static void driDestroyDrawable(__DRIdrawable
*drawable
);
70 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
73 * Is called from the drivers.
75 * \param f \c printf like format string.
78 __driUtilMessage(const char *f
, ...)
82 if (getenv("LIBGL_DEBUG")) {
83 fprintf(stderr
, "libGL error: \n");
85 vfprintf(stderr
, f
, args
);
87 fprintf(stderr
, "\n");
92 /*****************************************************************/
93 /** \name Context (un)binding functions */
94 /*****************************************************************/
100 * \param scrn the screen.
103 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
106 * This function calls __DriverAPIRec::UnbindContext, and then decrements
107 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
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.
113 static GLboolean
driUnbindContext(__DRIcontext
*ctx
)
115 __DRIcontextPrivate
*pcp
;
116 __DRIscreenPrivate
*psp
;
117 __DRIdrawablePrivate
*pdp
;
118 __DRIdrawablePrivate
*prp
;
121 ** Assume error checking is done properly in glXMakeCurrent before
122 ** calling driUnbindContext.
128 pcp
= (__DRIcontextPrivate
*)ctx
->private;
129 psp
= (__DRIscreenPrivate
*)pcp
->driScreenPriv
;
130 pdp
= (__DRIdrawablePrivate
*)pcp
->driDrawablePriv
;
131 prp
= (__DRIdrawablePrivate
*)pcp
->driReadablePriv
;
133 /* Let driver unbind drawable from context */
134 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
136 if (pdp
->refcount
== 0) {
144 if (prp
->refcount
== 0) {
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)
158 /* Unbind the drawable */
159 pcp
->driDrawablePriv
= NULL
;
160 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
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
172 static GLboolean
DoBindContext(__DRIcontext
*ctx
,
173 __DRIdrawable
*pdraw
,
174 __DRIdrawable
*pread
)
176 __DRIdrawablePrivate
*pdp
;
177 __DRIdrawablePrivate
*prp
;
178 __DRIcontextPrivate
* const pcp
= ctx
->private;
179 __DRIscreenPrivate
*psp
= pcp
->driScreenPriv
;
181 pdp
= (__DRIdrawablePrivate
*) pdraw
->private;
182 prp
= (__DRIdrawablePrivate
*) pread
->private;
184 /* Bind the drawable to the context */
185 pcp
->driDrawablePriv
= pdp
;
186 pcp
->driReadablePriv
= prp
;
187 pdp
->driContextPriv
= pcp
;
194 ** Now that we have a context associated with this drawable, we can
195 ** initialize the drawable information if has not been done before.
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
);
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
);
209 /* Call device-specific MakeCurrent */
210 (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, prp
);
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
221 static GLboolean
driBindContext(__DRIcontext
* ctx
,
222 __DRIdrawable
*pdraw
,
223 __DRIdrawable
*pread
)
226 ** Assume error checking is done properly in glXMakeCurrent before
227 ** calling driBindContext.
230 if (ctx
== NULL
|| pdraw
== None
|| pread
== None
)
233 return DoBindContext( ctx
, pdraw
, pread
);
238 /*****************************************************************/
239 /** \name Drawable handling functions */
240 /*****************************************************************/
244 * Update private drawable information.
246 * \param pdp pointer to the private drawable information to update.
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
256 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate
*pdp
)
258 __DRIscreenPrivate
*psp
;
259 __DRIcontextPrivate
*pcp
= pdp
->driContextPriv
;
262 || ((pdp
!= pcp
->driDrawablePriv
) && (pdp
!= pcp
->driReadablePriv
))) {
264 * ...but we must ignore it. There can be many contexts bound to a
269 psp
= pdp
->driScreenPriv
;
272 _mesa_problem(NULL
, "Warning! Possible infinite loop due to bug "
273 "in file %s, line %d\n",
278 if (pdp
->pClipRects
) {
279 _mesa_free(pdp
->pClipRects
);
280 pdp
->pClipRects
= NULL
;
283 if (pdp
->pBackClipRects
) {
284 _mesa_free(pdp
->pBackClipRects
);
285 pdp
->pBackClipRects
= NULL
;
288 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
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
,
296 &pdp
->numBackClipRects
,
297 &pdp
->pBackClipRects
)) {
298 /* Error -- eg the window may have been destroyed. Keep going
301 pdp
->pStamp
= &pdp
->lastStamp
; /* prevent endless loop */
302 pdp
->numClipRects
= 0;
303 pdp
->pClipRects
= NULL
;
304 pdp
->numBackClipRects
= 0;
305 pdp
->pBackClipRects
= NULL
;
308 pdp
->pStamp
= &(psp
->pSAREA
->drawableTable
[pdp
->index
].stamp
);
310 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
316 /*****************************************************************/
317 /** \name GLX callbacks */
318 /*****************************************************************/
324 * \param drawablePrivate opaque pointer to the per-drawable private info.
327 * This function calls __DRIdrawablePrivate::swapBuffers.
329 * Is called directly from glXSwapBuffers().
331 static void driSwapBuffers(__DRIdrawable
*drawable
)
333 __DRIdrawablePrivate
*dPriv
= drawable
->private;
334 drm_clip_rect_t rect
;
336 dPriv
->swapBuffers(dPriv
);
338 /* Check that we actually have the new damage report method */
339 if (api_ver
< 20070105 || dri_interface
->reportDamage
== NULL
)
342 /* Assume it's affecting the whole drawable for now */
345 rect
.x2
= rect
.x1
+ dPriv
->w
;
346 rect
.y2
= rect
.y1
+ dPriv
->h
;
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
352 (*dri_interface
->reportDamage
)(dPriv
->pdraw
, dPriv
->x
, dPriv
->y
,
357 * Called directly from a number of higher-level GLX functions.
359 static int driGetMSC( __DRIscreen
*screen
, int64_t *msc
)
361 __DRIscreenPrivate
*sPriv
= screen
->private;
363 return sPriv
->DriverAPI
.GetMSC( sPriv
, msc
);
367 * Called directly from a number of higher-level GLX functions.
369 static int driGetSBC(__DRIdrawable
*drawable
, int64_t *sbc
)
371 __DRIdrawablePrivate
*dPriv
= drawable
->private;
376 status
= dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dPriv
, & sInfo
);
377 *sbc
= sInfo
.swap_count
;
382 static int driWaitForSBC(__DRIdrawable
*drawable
, int64_t target_sbc
,
383 int64_t * msc
, int64_t * sbc
)
385 __DRIdrawablePrivate
*dPriv
= drawable
->private;
387 return dPriv
->driScreenPriv
->DriverAPI
.WaitForSBC( dPriv
, target_sbc
,
391 static int driWaitForMSC(__DRIdrawable
*drawable
, int64_t target_msc
,
392 int64_t divisor
, int64_t remainder
,
393 int64_t * msc
, int64_t * sbc
)
395 __DRIdrawablePrivate
*dPriv
= drawable
->private;
400 status
= dPriv
->driScreenPriv
->DriverAPI
.WaitForMSC( dPriv
, target_msc
,
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.
409 && dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo
) {
410 status
= dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dPriv
, & sInfo
);
411 *sbc
= sInfo
.swap_count
;
417 static int64_t driSwapBuffersMSC(__DRIdrawable
*drawable
, int64_t target_msc
,
418 int64_t divisor
, int64_t remainder
)
420 __DRIdrawablePrivate
*dPriv
= drawable
->private;
422 return dPriv
->driScreenPriv
->DriverAPI
.SwapBuffersMSC( dPriv
, target_msc
,
427 static void driCopySubBuffer(__DRIdrawable
*drawable
,
428 int x
, int y
, int w
, int h
)
430 __DRIdrawablePrivate
*dPriv
= drawable
->private;
431 dPriv
->driScreenPriv
->DriverAPI
.CopySubBuffer(dPriv
, x
, y
, w
, h
);
435 * This is called via __DRIscreenRec's createNewDrawable pointer.
437 static void *driCreateNewDrawable(__DRIscreen
*screen
,
438 const __GLcontextModes
*modes
,
439 __DRIdrawable
*pdraw
,
440 drm_drawable_t hwDrawable
,
444 __DRIscreenPrivate
*psp
;
445 __DRIdrawablePrivate
*pdp
;
448 pdraw
->private = NULL
;
450 /* Since pbuffers are not yet supported, no drawable attributes are
455 pdp
= (__DRIdrawablePrivate
*)_mesa_malloc(sizeof(__DRIdrawablePrivate
));
460 pdp
->hHWDrawable
= hwDrawable
;
470 pdp
->numClipRects
= 0;
471 pdp
->numBackClipRects
= 0;
472 pdp
->pClipRects
= NULL
;
473 pdp
->pBackClipRects
= NULL
;
475 psp
= (__DRIscreenPrivate
*)screen
->private;
476 pdp
->driScreenPriv
= psp
;
477 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
479 if (!(*psp
->DriverAPI
.CreateBuffer
)(psp
, pdp
, modes
,
480 renderType
== GLX_PIXMAP_BIT
)) {
485 pdraw
->private = pdp
;
486 pdraw
->destroyDrawable
= driDestroyDrawable
;
487 pdraw
->swapBuffers
= driSwapBuffers
; /* called by glXSwapBuffers() */
489 pdraw
->getSBC
= driGetSBC
;
490 pdraw
->waitForSBC
= driWaitForSBC
;
491 pdraw
->waitForMSC
= driWaitForMSC
;
492 pdraw
->swapBuffersMSC
= driSwapBuffersMSC
;
493 pdraw
->frameTracking
= NULL
;
494 pdraw
->queryFrameTracking
= driQueryFrameTracking
;
496 if (driCompareGLXAPIVersion (20060314) >= 0)
497 pdraw
->copySubBuffer
= driCopySubBuffer
;
499 /* This special default value is replaced with the configured
500 * default value when the drawable is first bound to a direct
503 pdraw
->swap_interval
= (unsigned)-1;
505 pdp
->swapBuffers
= psp
->DriverAPI
.SwapBuffers
;
511 driDestroyDrawable(__DRIdrawable
*drawable
)
513 __DRIdrawablePrivate
*pdp
= drawable
->private;
514 __DRIscreenPrivate
*psp
;
517 psp
= pdp
->driScreenPriv
;
518 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
519 if (pdp
->pClipRects
) {
520 _mesa_free(pdp
->pClipRects
);
521 pdp
->pClipRects
= NULL
;
523 if (pdp
->pBackClipRects
) {
524 _mesa_free(pdp
->pBackClipRects
);
525 pdp
->pBackClipRects
= NULL
;
534 /*****************************************************************/
535 /** \name Context handling functions */
536 /*****************************************************************/
540 * Destroy the per-context private information.
542 * \param contextPrivate opaque pointer to the per-drawable private info.
545 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
546 * drmDestroyContext(), and finally frees \p contextPrivate.
549 driDestroyContext(__DRIcontext
*context
)
551 __DRIcontextPrivate
*pcp
= context
->private;
554 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
561 * Create the per-drawable private driver information.
563 * \param dpy The display handle.
564 * \param modes Mode used to create the new context.
565 * \param render_type Type of rendering target. \c GLX_RGBA is the only
566 * type likely to ever be supported for direct-rendering.
567 * \param sharedPrivate The shared context dependent methods or \c NULL if
569 * \param pctx DRI context to receive the context dependent methods.
571 * \returns An opaque pointer to the per-context private information on
572 * success, or \c NULL on failure.
575 * This function allocates and fills a __DRIcontextPrivateRec structure. It
576 * performs some device independent initialization and passes all the
577 * relevent information to __DriverAPIRec::CreateContext to create the
582 driCreateNewContext(__DRIscreen
*screen
, const __GLcontextModes
*modes
,
583 int render_type
, void *sharedPrivate
,
584 drm_context_t hwContext
, __DRIcontext
*pctx
)
586 __DRIcontextPrivate
*pcp
;
587 __DRIcontextPrivate
*pshare
= (__DRIcontextPrivate
*) sharedPrivate
;
588 __DRIscreenPrivate
*psp
;
589 void * const shareCtx
= (pshare
!= NULL
) ? pshare
->driverPrivate
: NULL
;
591 psp
= (__DRIscreenPrivate
*)screen
->private;
593 pcp
= (__DRIcontextPrivate
*)_mesa_malloc(sizeof(__DRIcontextPrivate
));
598 pcp
->hHWContext
= hwContext
;
599 pcp
->driScreenPriv
= psp
;
600 pcp
->driDrawablePriv
= NULL
;
602 /* When the first context is created for a screen, initialize a "dummy"
606 if (!psp
->dummyContextPriv
.driScreenPriv
) {
607 psp
->dummyContextPriv
.hHWContext
= psp
->pSAREA
->dummy_context
;
608 psp
->dummyContextPriv
.driScreenPriv
= psp
;
609 psp
->dummyContextPriv
.driDrawablePriv
= NULL
;
610 psp
->dummyContextPriv
.driverPrivate
= NULL
;
611 /* No other fields should be used! */
614 pctx
->destroyContext
= driDestroyContext
;
615 pctx
->bindContext
= driBindContext
;
616 pctx
->unbindContext
= driUnbindContext
;
618 if ( !(*psp
->DriverAPI
.CreateContext
)(modes
, pcp
, shareCtx
) ) {
628 /*****************************************************************/
629 /** \name Screen handling functions */
630 /*****************************************************************/
634 * Destroy the per-screen private information.
636 * \param dpy the display handle.
637 * \param scrn the screen number.
638 * \param screenPrivate opaque pointer to the per-screen private information.
641 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
642 * drmClose(), and finally frees \p screenPrivate.
644 static void driDestroyScreen(__DRIscreen
*screen
)
646 __DRIscreenPrivate
*psp
= screen
->private;
649 /* No interaction with the X-server is possible at this point. This
650 * routine is called after XCloseDisplay, so there is no protocol
651 * stream open to the X-server anymore.
654 if (psp
->DriverAPI
.DestroyScreen
)
655 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
657 (void)drmUnmap((drmAddress
)psp
->pSAREA
, SAREA_MAX
);
658 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
659 (void)drmCloseOnce(psp
->fd
);
667 * This is the bootstrap function for the driver. libGL supplies all of the
668 * requisite information about the system, and the driver initializes itself.
669 * This routine also fills in the linked list pointed to by \c driver_modes
670 * with the \c __GLcontextModes that the driver can support for windows or
673 * \param scrn Index of the screen
674 * \param psc DRI screen data (not driver private)
675 * \param modes Linked list of known display modes. This list is, at a
676 * minimum, a list of modes based on the current display mode.
677 * These roughly match the set of available X11 visuals, but it
678 * need not be limited to X11! The calling libGL should create
679 * a list that will inform the driver of the current display
680 * mode (i.e., color buffer depth, depth buffer depth, etc.).
681 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
683 * \param dri_version Version of the "server-side" DRI.
684 * \param drm_version Version of the kernel DRM.
685 * \param frame_buffer Data describing the location and layout of the
687 * \param pSAREA Pointer the the SAREA.
688 * \param fd Device handle for the DRM.
689 * \param internal_api_version Version of the internal interface between the
691 * \param driverAPI Driver API functions used by other routines in dri_util.c.
693 * \note There is no need to check the minimum API version in this
694 * function. Since the name of this function is versioned, it is
695 * impossible for a loader that is too old to even load this driver.
698 void * __DRI_CREATE_NEW_SCREEN( int scrn
, __DRIscreen
*psc
,
699 const __DRIversion
* ddx_version
,
700 const __DRIversion
* dri_version
,
701 const __DRIversion
* drm_version
,
702 const __DRIframebuffer
* frame_buffer
,
703 drmAddress pSAREA
, int fd
,
704 int internal_api_version
,
705 const __DRIinterfaceMethods
* interface
,
706 __GLcontextModes
** driver_modes
)
709 __DRIscreenPrivate
*psp
;
711 dri_interface
= interface
;
712 api_ver
= internal_api_version
;
714 psp
= _mesa_malloc(sizeof(*psp
));
721 ** NOT_DONE: This is used by the X server to detect when the client
722 ** has died while holding the drawable lock. The client sets the
723 ** drawable lock to this value.
727 psp
->drm_version
= *drm_version
;
728 psp
->ddx_version
= *ddx_version
;
729 psp
->dri_version
= *dri_version
;
731 psp
->pSAREA
= pSAREA
;
733 psp
->pFB
= frame_buffer
->base
;
734 psp
->fbSize
= frame_buffer
->size
;
735 psp
->fbStride
= frame_buffer
->stride
;
736 psp
->fbWidth
= frame_buffer
->width
;
737 psp
->fbHeight
= frame_buffer
->height
;
738 psp
->devPrivSize
= frame_buffer
->dev_priv_size
;
739 psp
->pDevPriv
= frame_buffer
->dev_priv
;
740 psp
->fbBPP
= psp
->fbStride
* 8 / frame_buffer
->width
;
746 ** Do not init dummy context here; actual initialization will be
747 ** done when the first DRI context is created. Init screen priv ptr
748 ** to NULL to let CreateContext routine that it needs to be inited.
750 psp
->dummyContextPriv
.driScreenPriv
= NULL
;
752 psc
->destroyScreen
= driDestroyScreen
;
753 psc
->createNewDrawable
= driCreateNewDrawable
;
754 psc
->getMSC
= driGetMSC
;
755 psc
->createNewContext
= driCreateNewContext
;
757 if (internal_api_version
>= 20070121)
758 psc
->setTexOffset
= psp
->DriverAPI
.setTexOffset
;
760 *driver_modes
= __driDriverInitScreen(psp
);
761 if (*driver_modes
== NULL
) {
770 * Compare the current GLX API version with a driver supplied required version.
772 * The minimum required version is compared with the API version exported by
773 * the \c __glXGetInternalVersion function (in libGL.so).
775 * \param required_version Minimum required internal GLX API version.
776 * \return A tri-value return, as from strcmp is returned. A value less
777 * than, equal to, or greater than zero will be returned if the
778 * internal GLX API version is less than, equal to, or greater
779 * than \c required_version.
781 * \sa __glXGetInternalVersion().
783 int driCompareGLXAPIVersion( GLint required_version
)
785 if ( api_ver
> required_version
) {
788 else if ( api_ver
== required_version
) {
797 driQueryFrameTracking(__DRIdrawable
*drawable
,
798 int64_t * sbc
, int64_t * missedFrames
,
799 float * lastMissedUsage
, float * usage
)
804 __DRIdrawablePrivate
* dpriv
= drawable
->private;
807 status
= dpriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dpriv
, & sInfo
);
809 *sbc
= sInfo
.swap_count
;
810 *missedFrames
= sInfo
.swap_missed_count
;
811 *lastMissedUsage
= sInfo
.swap_missed_usage
;
813 (*dri_interface
->getUST
)( & ust
);
814 *usage
= driCalculateSwapUsage( dpriv
, sInfo
.swap_ust
, ust
);
822 * Calculate amount of swap interval used between GLX buffer swaps.
824 * The usage value, on the range [0,max], is the fraction of total swap
825 * interval time used between GLX buffer swaps is calculated.
827 * \f$p = t_d / (i * t_r)\f$
829 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
830 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
831 * required for a single vertical refresh period (as returned by \c
834 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
837 * \param dPriv Pointer to the private drawable structure.
838 * \return If less than a single swap interval time period was required
839 * between GLX buffer swaps, a number greater than 0 and less than
840 * 1.0 is returned. If exactly one swap interval time period is
841 * required, 1.0 is returned, and if more than one is required then
842 * a number greater than 1.0 will be returned.
844 * \sa glXSwapIntervalSGI glXGetMscRateOML
846 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
847 * be possible to cache the sync rate?
850 driCalculateSwapUsage( __DRIdrawablePrivate
*dPriv
, int64_t last_swap_ust
,
851 int64_t current_ust
)
859 if ( (*dri_interface
->getMSCRate
)(dPriv
->pdraw
, &n
, &d
) ) {
860 interval
= (dPriv
->pdraw
->swap_interval
!= 0)
861 ? dPriv
->pdraw
->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
);