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 <c...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev