[Mesa-dev] [PATCH 2/2] glx/dri2: Add support for adaptive vsync
Lauri Kasanen
cand at gmx.com
Sun Dec 15 02:38:28 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.
v2:
- Removed mistaken EGL X11 lines
- Added hysteresis
- Faster sync
Signed-off-by: Lauri Kasanen <cand at gmx.com>
---
src/egl/drivers/dri2/egl_dri2.h | 1 +
src/egl/drivers/dri2/platform_wayland.c | 3 ++
src/egl/drivers/dri2/platform_x11.c | 3 ++
src/glx/dri2_glx.c | 63 +++++++++++++++++++++++++
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, 78 insertions(+), 1 deletion(-)
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index d29dd98..d710e84 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -225,6 +225,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..4679830 100644
--- a/src/egl/drivers/dri2/platform_x11.c
+++ b/src/egl/drivers/dri2/platform_x11.c
@@ -1097,6 +1097,9 @@ 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:
+ 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/glx/dri2_glx.c b/src/glx/dri2_glx.c
index bfeebed..b41dd1e 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,42 @@ 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;
+
+ unsigned int rate = scr->refresh_rate ? scr->refresh_rate : 60;
+ unsigned int high, low;
+ struct timeval tv;
+ uint64_t current_time;
+
+ rate /= 2;
+
+ /* Hysteresis */
+ high = rate * 1.1f;
+ low = rate * 0.9f;
+
+ gettimeofday(&tv, 0);
+ current_time = (uint64_t)tv.tv_sec*1000000 + (uint64_t)tv.tv_usec;
+
+ draw->adaptive_frames++;
+
+ if (draw->adaptive_previous_time + 500000 <= current_time) {
+ if (draw->adaptive_frames >= high) {
+ /* Enable vsync */
+ if (scr->vtable.setSwapInterval)
+ scr->vtable.setSwapInterval(&draw->base, 1);
+ } else if (draw->adaptive_frames <= low) {
+ /* 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 +898,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 +1205,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 +1341,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