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

Kristian Hoegsberg hoegsberg at gmail.com
Tue Mar 20 17:02:24 PDT 2012


On Tue, Mar 20, 2012 at 11:54:56AM +0200, Ander Conselvan de Oliveira wrote:
> 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.

Yikes, ok.  I think the patch is ok, though I'd prefer to make
wl_event_loop_dispatch() return "number of events dispatched" or maybe
just 1 if it dispatched any events, and then iterate until it returns
0.  Since we already have to do O_NONBLOCK for mtdev, lets just go
with this (but I'll note for the record that I really don't like that
aspect of mtdev, and it doesn't have to do that).

Kristian

> ---
>  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
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list