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.
dev
Ander Conselvan de Oliveira 13 years ago committed by Kristian Høgsberg
parent afee221ccb
commit 29d955685f
  1. 65
      src/evdev.c

@ -322,35 +322,18 @@ evdev_flush_motion(struct evdev_input_device *device, uint32_t time)
device->type &= ~EVDEV_ABSOLUTE_MOTION; device->type &= ~EVDEV_ABSOLUTE_MOTION;
} }
} }
#define NUM_EVENTS 8
static int static void
evdev_input_device_data(int fd, uint32_t mask, void *data) evdev_process_events(struct evdev_input_device *device,
struct input_event *ev, int count)
{ {
struct weston_compositor *ec; struct input_event *e, *end;
struct evdev_input_device *device = data;
struct input_event ev[NUM_EVENTS], *e, *end;
int len;
uint32_t time = 0; 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; device->type = 0;
e = ev; e = ev;
end = (void *) ev + len; end = e + count;
for (e = ev; e < end; e++) { for (e = ev; e < end; e++) {
time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; 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); 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; return 1;
} }
/* copied from udev/extras/input_id/input_id.c */ /* copied from udev/extras/input_id/input_id.c */
/* we must use this kernel-compatible implementation */ /* we must use this kernel-compatible implementation */
#define BITS_PER_LONG (sizeof(unsigned long) * 8) #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.dx = 0;
device->rel.dy = 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); device->fd = open(path, O_RDONLY | O_NONBLOCK);
if (device->fd < 0) if (device->fd < 0)
goto err0; goto err0;

Loading…
Cancel
Save