compositor: Only process input once per frame

When we're repainting, there's no point in polling for input events.
We just read input events once before each repaint and send out events
as needed.  The input events come with an accurate timestamp, so this
doesn't affect the timing information and client should always look at
the event timestamps if they're trying to determine pointer motion
speed or double click speed.  If we go idle (stop repainting) we add the
input devices back into the primary main loop and wait for the next event.

This avoids waking up the compositor separately (one or more times per
frame) to handle input events.  We also avoid updating cursor position
and other compositor state after the client has rendered its new
frame, reducing lag between what the client renders and the pointer
position.
This commit is contained in:
Kristian Høgsberg 2012-03-05 19:50:08 -05:00
parent 7ea10864c2
commit 7dbf5e2ea7
1 changed files with 37 additions and 28 deletions

View File

@ -973,25 +973,46 @@ weston_output_repaint(struct weston_output *output, int msecs)
animation->frame(animation, output, msecs);
}
static void
idle_repaint(void *data)
static int
weston_compositor_read_input(int fd, uint32_t mask, void *data)
{
struct weston_output *output = data;
struct weston_compositor *compositor = data;
/* An idle repaint may have been cancelled by vt switching away. */
if (output->repaint_needed)
weston_output_repaint(output, weston_compositor_get_time());
else
output->repaint_scheduled = 0;
wl_event_loop_dispatch(compositor->input_loop, 0);
return 1;
}
WL_EXPORT void
weston_output_finish_frame(struct weston_output *output, int msecs)
{
if (output->repaint_needed)
struct weston_compositor *compositor = output->compositor;
struct wl_event_loop *loop =
wl_display_get_event_loop(compositor->wl_display);
int fd;
wl_event_loop_dispatch(compositor->input_loop, 0);
if (output->repaint_needed) {
weston_output_repaint(output, msecs);
else
output->repaint_scheduled = 0;
return;
}
output->repaint_scheduled = 0;
if (compositor->input_loop_source)
return;
fd = wl_event_loop_get_fd(compositor->input_loop);
compositor->input_loop_source =
wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
weston_compositor_read_input, compositor);
}
static void
idle_repaint(void *data)
{
struct weston_output *output = data;
weston_output_finish_frame(output, weston_compositor_get_time());
}
WL_EXPORT void
@ -1019,6 +1040,11 @@ weston_compositor_schedule_repaint(struct weston_compositor *compositor)
wl_event_loop_add_idle(loop, idle_repaint, output);
output->repaint_scheduled = 1;
}
if (compositor->input_loop_source) {
wl_event_source_remove(compositor->input_loop_source);
compositor->input_loop_source = NULL;
}
}
WL_EXPORT void
@ -2268,16 +2294,6 @@ compositor_bind(struct wl_client *client,
&compositor_interface, id, compositor);
}
static int
weston_compositor_read_input(int fd, uint32_t mask, void *data)
{
struct weston_compositor *compositor = data;
wl_event_loop_dispatch(compositor->input_loop, 0);
return 1;
}
WL_EXPORT int
weston_compositor_init(struct weston_compositor *ec, struct wl_display *display)
{
@ -2349,13 +2365,6 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display)
ec->input_loop = wl_event_loop_create();
ec->input_loop_source =
wl_event_loop_add_fd(loop,
wl_event_loop_get_fd(ec->input_loop),
WL_EVENT_READABLE,
weston_compositor_read_input, ec);
weston_compositor_schedule_repaint(ec);
return 0;