diff options
author | Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com> | 2012-03-20 19:52:57 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@bitplanet.net> | 2012-03-20 22:43:57 -0400 |
commit | 29d955685f26d3d0b7657ec5d5dbf9ecc6ca3c1a (patch) | |
tree | c153d7eeebf0282aedf665c7110703f3d69ad6e9 | |
parent | afee221ccb6b34b75528e518a725a7fd24f464df (diff) |
evdev: fix input lag when processing input from output repaint
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.
-rw-r--r-- | src/evdev.c | 65 |
1 files changed, 41 insertions, 24 deletions
diff --git a/src/evdev.c b/src/evdev.c index 9b8d756a..e0a59668 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -322,35 +322,18 @@ evdev_flush_motion(struct evdev_input_device *device, uint32_t time) device->type &= ~EVDEV_ABSOLUTE_MOTION; } } -#define NUM_EVENTS 8 -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[NUM_EVENTS], *e, *end; - int len; + struct input_event *e, *end; uint32_t time = 0; - ec = device->master->base.compositor; - if (!ec->focus) - return 1; - - if (device->mtdev) - len = mtdev_get(device->mtdev, fd, ev, NUM_EVENTS) * - sizeof (struct input_event); - else - 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; @@ -373,11 +356,43 @@ 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[32]; + 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 { + if (device->mtdev) + len = mtdev_get(device->mtdev, fd, ev, + ARRAY_LENGTH(ev)) * + sizeof (struct input_event); + else + 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; } - /* copied from udev/extras/input_id/input_id.c */ /* we must use this kernel-compatible implementation */ #define BITS_PER_LONG (sizeof(unsigned long) * 8) @@ -463,7 +478,9 @@ evdev_input_device_create(struct evdev_input *master, device->rel.dx = 0; device->rel.dy = 0; - /* if O_NONBLOCK is not set, mtdev_get() blocks */ + /* Use non-blocking mode so that we can loop on read on + * evdev_input_device_data() until all events on the fd are + * read. mtdev_get() also expects this. */ device->fd = open(path, O_RDONLY | O_NONBLOCK); if (device->fd < 0) goto err0; |