summaryrefslogtreecommitdiffstats
path: root/src/mesa/drivers/dri/common/vblank.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/common/vblank.c')
-rw-r--r--src/mesa/drivers/dri/common/vblank.c129
1 files changed, 88 insertions, 41 deletions
diff --git a/src/mesa/drivers/dri/common/vblank.c b/src/mesa/drivers/dri/common/vblank.c
index eebe42d96a1..e7ed545f13c 100644
--- a/src/mesa/drivers/dri/common/vblank.c
+++ b/src/mesa/drivers/dri/common/vblank.c
@@ -210,20 +210,6 @@ GLuint driGetDefaultVBlankFlags( const driOptionCache *optionCache )
/****************************************************************************/
/**
- * Sets the default swap interval when the drawable is first bound to a
- * direct rendering context.
- */
-
-void driDrawableInitVBlank( __DRIdrawablePrivate *priv, GLuint flags )
-{
- if ( priv->pdraw->swap_interval == (unsigned)-1 ) {
- priv->pdraw->swap_interval = (flags & VBLANK_FLAG_THROTTLE) != 0 ? 1 : 0;
- }
-}
-
-
-/****************************************************************************/
-/**
* Wrapper to call \c drmWaitVBlank. The main purpose of this function is to
* wrap the error message logging. The error message should only be logged
* the first time the \c drmWaitVBlank fails. If \c drmWaitVBlank is
@@ -262,6 +248,71 @@ static int do_wait( drmVBlank * vbl, GLuint * vbl_seq, int fd )
/****************************************************************************/
/**
+ * Sets the default swap interval when the drawable is first bound to a
+ * direct rendering context.
+ */
+
+void driDrawableInitVBlank( __DRIdrawablePrivate *priv, GLuint flags,
+ GLuint *vbl_seq )
+{
+ if ( priv->pdraw->swap_interval == (unsigned)-1 ) {
+ /* Get current vertical blank sequence */
+ drmVBlank vbl = { .request={ .type = DRM_VBLANK_RELATIVE, .sequence = 0 } };
+ do_wait( &vbl, vbl_seq, priv->driScreenPriv->fd );
+
+ priv->pdraw->swap_interval = (flags & (VBLANK_FLAG_THROTTLE |
+ VBLANK_FLAG_SYNC)) != 0 ? 1 : 0;
+ }
+}
+
+
+/****************************************************************************/
+/**
+ * Returns the current swap interval of the given drawable.
+ */
+
+unsigned
+driGetVBlankInterval( const __DRIdrawablePrivate *priv, GLuint flags )
+{
+ if ( (flags & VBLANK_FLAG_INTERVAL) != 0 ) {
+ /* this must have been initialized when the drawable was first bound
+ * to a direct rendering context. */
+ assert ( priv->pdraw->swap_interval != (unsigned)-1 );
+
+ return priv->pdraw->swap_interval;
+ }
+ else if ( (flags & (VBLANK_FLAG_THROTTLE | VBLANK_FLAG_SYNC)) != 0 ) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+/****************************************************************************/
+/**
+ * Returns the current vertical blank sequence number of the given drawable.
+ */
+
+void
+driGetCurrentVBlank( const __DRIdrawablePrivate *priv, GLuint flags,
+ GLuint *vbl_seq )
+{
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ if ( flags & VBLANK_FLAG_SECONDARY ) {
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ }
+ vbl.request.sequence = 0;
+
+ (void) do_wait( &vbl, vbl_seq, priv->driScreenPriv->fd );
+}
+
+
+/****************************************************************************/
+/**
* Waits for the vertical blank for use with glXSwapBuffers.
*
* \param vbl_seq Vertical blank sequence number (MSC) after the last buffer
@@ -282,7 +333,7 @@ driWaitForVBlank( const __DRIdrawablePrivate *priv, GLuint * vbl_seq,
unsigned original_seq;
unsigned deadline;
unsigned interval;
-
+ unsigned diff;
*missed_deadline = GL_FALSE;
if ( (flags & (VBLANK_FLAG_INTERVAL |
@@ -304,44 +355,40 @@ driWaitForVBlank( const __DRIdrawablePrivate *priv, GLuint * vbl_seq,
*/
original_seq = *vbl_seq;
+ interval = driGetVBlankInterval(priv, flags);
+ deadline = original_seq + interval;
- vbl.request.sequence = ((flags & VBLANK_FLAG_SYNC) != 0) ? 1 : 0;
vbl.request.type = DRM_VBLANK_RELATIVE;
-
+ if ( flags & VBLANK_FLAG_SECONDARY ) {
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ }
+ vbl.request.sequence = ((flags & VBLANK_FLAG_SYNC) != 0) ? 1 : 0;
+
if ( do_wait( & vbl, vbl_seq, priv->driScreenPriv->fd ) != 0 ) {
return -1;
}
-
- vbl.request.type = DRM_VBLANK_ABSOLUTE;
+ diff = *vbl_seq - deadline;
- if ( (flags & VBLANK_FLAG_INTERVAL) != 0 ) {
- interval = priv->pdraw->swap_interval;
- /* this must have been initialized when the drawable was first bound
- * to a direct rendering context. */
- assert ( interval != (unsigned)-1 );
- }
- else if ( (flags & VBLANK_FLAG_THROTTLE) != 0 ) {
- interval = 1;
- }
- else {
- interval = 0;
+ /* No need to wait again if we've already reached the target */
+ if (diff <= (1 << 23)) {
+ *missed_deadline = (flags & VBLANK_FLAG_SYNC) ? (diff > 0) : GL_TRUE;
+ return 0;
}
+ /* Wait until the target vertical blank. */
+ vbl.request.type = DRM_VBLANK_ABSOLUTE;
+ if ( flags & VBLANK_FLAG_SECONDARY ) {
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ }
+ vbl.request.sequence = deadline;
- /* Wait until the next vertical blank. If the interval is zero, then
- * the deadline is one vertical blank after the previous wait.
- */
-
- vbl.request.sequence = original_seq + interval;
- if ( *vbl_seq < vbl.request.sequence ) {
- if ( do_wait( & vbl, vbl_seq, priv->driScreenPriv->fd ) != 0 ) {
- return -1;
- }
+ if ( do_wait( & vbl, vbl_seq, priv->driScreenPriv->fd ) != 0 ) {
+ return -1;
}
- deadline = original_seq + ((interval == 0) ? 1 : interval);
- *missed_deadline = ( *vbl_seq > deadline );
+ diff = *vbl_seq - deadline;
+ *missed_deadline = diff > 0 && diff <= (1 << 23);
return 0;
}