[PATCH] evdev: fix input lag when processing input from output repaint

Ander Conselvan de Oliveira ander.conselvan.de.oliveira at intel.com
Tue Mar 20 02:54:56 PDT 2012


When the compositor is in a repaint cycle, input is processed only once
per frame. However, a call to evdev_input_device_data() would handle at
most 8 events at time. When there was more than 8 events pending for a
given frame, input lag would occur. This was most visible with multi
touch input.

This patch changes the evdev_input_device_data() so that it will handle
all the events available in the fd. In order to do that, the fd is put
in non-blocking mode, so that it is possible to loop on read and stop
on EAGAIN instead of blocking.
---
 src/evdev.c |   53 +++++++++++++++++++++++++++++++++++------------------
 1 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 530eb6b..9997f5d 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -321,29 +321,17 @@ evdev_flush_motion(struct evdev_input_device *device, uint32_t time)
 	}
 }
 
-static int
-evdev_input_device_data(int fd, uint32_t mask, void *data)
+static void
+evdev_process_events(struct evdev_input_device *device,
+		     struct input_event *ev, int count)
 {
-	struct weston_compositor *ec;
-	struct evdev_input_device *device = data;
-	struct input_event ev[8], *e, *end;
-	int len;
+	struct input_event *e, *end;
 	uint32_t time = 0;
 
-	ec = device->master->base.compositor;
-	if (!ec->focus)
-		return 1;
-
-	len = read(fd, &ev, sizeof ev);
-	if (len < 0 || len % sizeof e[0] != 0) {
-		/* FIXME: call device_removed when errno is ENODEV. */;
-		return 1;
-	}
-
 	device->type = 0;
 
 	e = ev;
-	end = (void *) ev + len;
+	end = e + count;
 	for (e = ev; e < end; e++) {
 		time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
 
@@ -366,6 +354,33 @@ evdev_input_device_data(int fd, uint32_t mask, void *data)
 	}
 
 	evdev_flush_motion(device, time);
+}
+
+static int
+evdev_input_device_data(int fd, uint32_t mask, void *data)
+{
+	struct weston_compositor *ec;
+	struct evdev_input_device *device = data;
+	struct input_event ev[8];
+	int len;
+
+	ec = device->master->base.compositor;
+	if (!ec->focus)
+		return 1;
+
+	/* If the compositor is repainting, this function is called only once
+	 * per frame and we have to process all the events available on the
+	 * fd, otherwise there will be input lag. */
+	do {
+		len = read(fd, &ev, sizeof ev);
+		if (len < 0 || len % sizeof ev[0] != 0) {
+			/* FIXME: call device_removed when errno is ENODEV. */;
+			return 1;
+		}
+
+		evdev_process_events(device, ev, len / sizeof ev[0]);
+
+	} while (len > 0);
 
 	return 1;
 }
@@ -455,7 +470,9 @@ evdev_input_device_create(struct evdev_input *master,
 	device->rel.dx = 0;
 	device->rel.dy = 0;
 
-	device->fd = open(path, O_RDONLY);
+	/* Use non-blocking mode so that we can loop on read on
+	 * evdev_input_device_data() until all events on the fd are read. */
+	device->fd = open(path, O_RDONLY | O_NONBLOCK);
 	if (device->fd < 0)
 		goto err0;
 
-- 
1.7.4.1



More information about the wayland-devel mailing list