[Mesa-dev] [PATCH 2/2] glx/dri2: Add support for adaptive vsync

Lauri Kasanen cand at gmx.com
Sat Dec 14 07:35:35 PST 2013


There is a GLX extension for this behavior, glx_swap_control_tear, which mesa doesn't
support ATM. But as usual, even after it becomes supported, there will be thousands
of applications that won't add support for it, necessitating the need for a user
override.

Signed-off-by: Lauri Kasanen <cand at gmx.com>
---
 src/egl/drivers/dri2/egl_dri2.h                 |  2 +
 src/egl/drivers/dri2/platform_wayland.c         |  3 ++
 src/egl/drivers/dri2/platform_x11.c             |  7 ++++
 src/glx/dri2_glx.c                              | 56 +++++++++++++++++++++++++
 src/glx/dri2_priv.h                             |  1 +
 src/glx/dri3_glx.c                              |  3 ++
 src/glx/dri3_priv.h                             |  1 +
 src/mesa/drivers/dri/common/xmlpool/t_options.h |  4 +-
 8 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index d29dd98..56abf0c 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -108,6 +108,7 @@ struct dri2_egl_display
    int                       min_swap_interval;
    int                       max_swap_interval;
    int                       default_swap_interval;
+   int                       adaptive_swap;
 #ifdef HAVE_DRM_PLATFORM
    struct gbm_dri_device    *gbm_dri;
 #endif
@@ -225,6 +226,7 @@ struct dri2_egl_image
 #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3
+#define DRI_CONF_VBLANK_ADAPTIVE 4
 
 /* standard typecasts */
 _EGL_DRIVER_STANDARD_TYPECASTS(dri2_egl)
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index 5c8440d..1d28fe7 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -941,6 +941,9 @@ dri2_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
       dri2_dpy->max_swap_interval = 1;
       dri2_dpy->default_swap_interval = 0;
       break;
+   case DRI_CONF_VBLANK_ADAPTIVE:
+      fprintf(stderr, "Adaptive vsync is not supported for this platform.\n");
+      /* fall-through */
    default:
    case DRI_CONF_VBLANK_DEF_INTERVAL_1:
       dri2_dpy->min_swap_interval = 0;
diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c
index d3397d4..309f692 100644
--- a/src/egl/drivers/dri2/platform_x11.c
+++ b/src/egl/drivers/dri2/platform_x11.c
@@ -1071,6 +1071,7 @@ dri2_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
     */
    dri2_dpy->min_swap_interval = 0;
    dri2_dpy->max_swap_interval = 0;
+   dri2_dpy->adaptive_swap = 0;
 
    if (!dri2_dpy->swap_available)
       return;
@@ -1097,6 +1098,12 @@ dri2_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
       dri2_dpy->max_swap_interval = arbitrary_max_interval;
       dri2_dpy->default_swap_interval = 0;
       break;
+   case DRI_CONF_VBLANK_ADAPTIVE:
+      dri2_dpy->min_swap_interval = 0;
+      dri2_dpy->max_swap_interval = 0;
+      dri2_dpy->default_swap_interval = 0;
+      dri2_dpy->adaptive_swap = 1;
+      break;
    default:
    case DRI_CONF_VBLANK_DEF_INTERVAL_1:
       dri2_dpy->min_swap_interval = 0;
diff --git a/src/glx/dri2_glx.c b/src/glx/dri2_glx.c
index bfeebed..c982cdc 100644
--- a/src/glx/dri2_glx.c
+++ b/src/glx/dri2_glx.c
@@ -57,6 +57,7 @@
 #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3
+#define DRI_CONF_VBLANK_ADAPTIVE 4
 
 #undef DRI2_MINOR
 #define DRI2_MINOR 1
@@ -95,9 +96,15 @@ struct dri2_drawable
    int have_back;
    int have_fake_front;
    int swap_interval;
+   int adaptive_swap;
 
+   /* For show_fps */
    uint64_t previous_time;
    unsigned frames;
+
+   /* For adaptive_vsync */
+   uint64_t adaptive_previous_time;
+   unsigned adaptive_frames;
 };
 
 static const struct glx_context_vtable dri2_context_vtable;
@@ -377,12 +384,17 @@ dri2CreateDrawable(struct glx_screen *base, XID xDrawable,
    pdraw->bufferCount = 0;
    pdraw->swap_interval = 1; /* default may be overridden below */
    pdraw->have_back = 0;
+   pdraw->adaptive_swap = 0;
 
    if (psc->config)
       psc->config->configQueryi(psc->driScreen,
 				"vblank_mode", &vblank_mode);
 
    switch (vblank_mode) {
+   case DRI_CONF_VBLANK_ADAPTIVE:
+      pdraw->swap_interval = 0;
+      pdraw->adaptive_swap = 1;
+      break;
    case DRI_CONF_VBLANK_NEVER:
    case DRI_CONF_VBLANK_DEF_INTERVAL_0:
       pdraw->swap_interval = 0;
@@ -770,6 +782,35 @@ static void show_fps(struct dri2_drawable *draw)
    }
 }
 
+static void adaptive_vsync(struct dri2_drawable *draw)
+{
+   const struct dri2_screen *scr = (struct dri2_screen *) draw->base.psc;
+
+   const int rate = scr->refresh_rate ? scr->refresh_rate : 60;
+   struct timeval tv;
+   uint64_t current_time;
+
+   gettimeofday(&tv, 0);
+   current_time = (uint64_t)tv.tv_sec*1000000 + (uint64_t)tv.tv_usec;
+
+   draw->adaptive_frames++;
+
+   if (draw->adaptive_previous_time + 1000000 <= current_time) {
+      if (draw->adaptive_frames >= rate - 1) {
+         /* Enable vsync */
+         if (scr->vtable.setSwapInterval)
+            scr->vtable.setSwapInterval(&draw->base, 1);
+      } else {
+         /* Disable vsync */
+         if (scr->vtable.setSwapInterval)
+            scr->vtable.setSwapInterval(&draw->base, 0);
+      }
+
+      draw->adaptive_frames = 0;
+      draw->adaptive_previous_time = current_time;
+   }
+}
+
 static int64_t
 dri2XcbSwapBuffers(Display *dpy,
                   __GLXDRIdrawable *pdraw,
@@ -850,6 +891,10 @@ dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
        show_fps(priv);
     }
 
+    if (priv->adaptive_swap) {
+       adaptive_vsync(priv);
+    }
+
     /* Old servers don't send invalidate events */
     if (!pdp->invalidateAvailable)
        dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);
@@ -1153,6 +1198,7 @@ dri2CreateScreen(int screen, struct glx_display * priv)
    char *driverName, *deviceName, *tmp;
    drm_magic_t magic;
    int i;
+   int numerator, denominator;
 
    psc = calloc(1, sizeof *psc);
    if (psc == NULL)
@@ -1288,6 +1334,16 @@ dri2CreateScreen(int screen, struct glx_display * priv)
    if (psc->show_fps_interval < 0)
       psc->show_fps_interval = 0;
 
+   /* Make the X call to query our refresh rate, for manual adaptive vsync. */
+   if (__glxGetMscRate(&psc->base, &numerator, &denominator)) {
+      if (denominator == 1) {
+         psc->refresh_rate = numerator;
+      } else {
+         float rate = ((float) numerator) / denominator;
+         psc->refresh_rate = rate;
+      }
+   }
+
    return &psc->base;
 
 handle_error:
diff --git a/src/glx/dri2_priv.h b/src/glx/dri2_priv.h
index c21eee5..886f74b 100644
--- a/src/glx/dri2_priv.h
+++ b/src/glx/dri2_priv.h
@@ -49,4 +49,5 @@ struct dri2_screen {
    int fd;
 
    int show_fps_interval;
+   int refresh_rate;
 };
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
index b047cc8..17394e5 100644
--- a/src/glx/dri3_glx.c
+++ b/src/glx/dri3_glx.c
@@ -306,6 +306,9 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
    case DRI_CONF_VBLANK_DEF_INTERVAL_0:
       pdraw->swap_interval = 0;
       break;
+   case DRI_CONF_VBLANK_ADAPTIVE:
+      fprintf(stderr, "Adaptive vsync is not supported for this platform.\n");
+      /* fall-through */
    case DRI_CONF_VBLANK_DEF_INTERVAL_1:
    case DRI_CONF_VBLANK_ALWAYS_SYNC:
    default:
diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h
index c892800..af86546 100644
--- a/src/glx/dri3_priv.h
+++ b/src/glx/dri3_priv.h
@@ -64,6 +64,7 @@
 #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3
+#define DRI_CONF_VBLANK_ADAPTIVE 4
 
 enum dri3_buffer_type {
    dri3_buffer_back = 0,
diff --git a/src/mesa/drivers/dri/common/xmlpool/t_options.h b/src/mesa/drivers/dri/common/xmlpool/t_options.h
index 3bf804a..2b04083 100644
--- a/src/mesa/drivers/dri/common/xmlpool/t_options.h
+++ b/src/mesa/drivers/dri/common/xmlpool/t_options.h
@@ -254,13 +254,15 @@ DRI_CONF_OPT_END
 #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3
+#define DRI_CONF_VBLANK_ADAPTIVE 4
 #define DRI_CONF_VBLANK_MODE(def) \
-DRI_CONF_OPT_BEGIN_V(vblank_mode,enum,def,"0:3") \
+DRI_CONF_OPT_BEGIN_V(vblank_mode,enum,def,"0:4") \
         DRI_CONF_DESC_BEGIN(en,gettext("Synchronization with vertical refresh (swap intervals)")) \
                 DRI_CONF_ENUM(0,gettext("Never synchronize with vertical refresh, ignore application's choice")) \
                 DRI_CONF_ENUM(1,gettext("Initial swap interval 0, obey application's choice")) \
                 DRI_CONF_ENUM(2,gettext("Initial swap interval 1, obey application's choice")) \
                 DRI_CONF_ENUM(3,gettext("Always synchronize with vertical refresh, application chooses the minimum swap interval")) \
+                DRI_CONF_ENUM(4,gettext("Adapt the vsync according to frame rate: for a 60hz display, tear for under 60fps, vsync for over 60fps")) \
         DRI_CONF_DESC_END \
 DRI_CONF_OPT_END
 
-- 
1.8.3.1



More information about the mesa-dev mailing list