summaryrefslogtreecommitdiff
path: root/src/libsystemd-terminal/grdev.c
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2014-09-20 11:12:44 +0200
committerDavid Herrmann <dh.herrmann@gmail.com>2014-09-20 11:46:49 +0200
commit7b12a45b2dc6993e3f31642df2cc9b528294da40 (patch)
treeeb078293c036af47c7b817f3c7a95ae50601576e /src/libsystemd-terminal/grdev.c
parent3ec19e5d91d3d705682fee62a509801737c56c1e (diff)
terminal: grdev: schedule virtual frame events if hw doesn't support it
Whenever we cannot use hardware frame events, we now schedule a virtual frame event to make sure applications don't have to do this. Usually, applications render only on data changes, but we can further reduce render-time by also limiting rendering to vsyncs.
Diffstat (limited to 'src/libsystemd-terminal/grdev.c')
-rw-r--r--src/libsystemd-terminal/grdev.c69
1 files changed, 60 insertions, 9 deletions
diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c
index 397da1b20..43d0c7c9b 100644
--- a/src/libsystemd-terminal/grdev.c
+++ b/src/libsystemd-terminal/grdev.c
@@ -574,6 +574,13 @@ grdev_pipe *grdev_find_pipe(grdev_card *card, const char *name) {
return hashmap_get(card->pipe_map, name);
}
+static int pipe_vsync_fn(sd_event_source *src, uint64_t usec, void *userdata) {
+ grdev_pipe *pipe = userdata;
+
+ grdev_pipe_frame(pipe);
+ return 0;
+}
+
int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) {
int r;
@@ -585,6 +592,7 @@ int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) {
assert_return(!pipe->cache, -EINVAL);
assert_return(pipe->width > 0, -EINVAL);
assert_return(pipe->height > 0, -EINVAL);
+ assert_return(pipe->vrefresh > 0, -EINVAL);
assert_return(!pipe->enabled, -EINVAL);
assert_return(!pipe->running, -EINVAL);
assert_return(name, -EINVAL);
@@ -605,6 +613,20 @@ int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) {
if (r < 0)
return r;
+ r = sd_event_add_time(pipe->card->session->context->event,
+ &pipe->vsync_src,
+ CLOCK_MONOTONIC,
+ 0,
+ 10 * USEC_PER_MSEC,
+ pipe_vsync_fn,
+ pipe);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_OFF);
+ if (r < 0)
+ return r;
+
r = hashmap_put(pipe->card->pipe_map, pipe->name, pipe);
if (r < 0)
return r;
@@ -633,6 +655,7 @@ grdev_pipe *grdev_pipe_free(grdev_pipe *pipe) {
tmp = *pipe;
pipe->vtable->free(pipe);
+ sd_event_source_unref(tmp.vsync_src);
grdev_tile_free(tmp.tile);
card_modified(tmp.card);
free(tmp.fbs);
@@ -676,17 +699,15 @@ void grdev_pipe_ready(grdev_pipe *pipe, bool running) {
pipe->running = running;
/* runtime events for unused pipes are not interesting */
- if (pipe->cache) {
+ if (pipe->cache && pipe->enabled) {
grdev_display *display = pipe->tile->display;
assert(display);
- if (running) {
- if (pipe->enabled)
- session_frame(display->session, display);
- } else {
+ if (running)
+ session_frame(display->session, display);
+ else
pipe->cache->incomplete = true;
- }
}
}
@@ -696,14 +717,44 @@ void grdev_pipe_frame(grdev_pipe *pipe) {
assert(pipe);
/* if pipe is unused, ignore any frame events */
- if (!pipe->cache)
+ if (!pipe->cache || !pipe->enabled)
return;
display = pipe->tile->display;
assert(display);
- if (pipe->enabled)
- session_frame(display->session, display);
+ grdev_pipe_schedule(pipe, 0);
+ session_frame(display->session, display);
+}
+
+void grdev_pipe_schedule(grdev_pipe *pipe, uint64_t frames) {
+ int r;
+ uint64_t ts;
+
+ if (!frames) {
+ sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_OFF);
+ return;
+ }
+
+ r = sd_event_now(pipe->card->session->context->event, CLOCK_MONOTONIC, &ts);
+ if (r < 0)
+ goto error;
+
+ ts += frames * USEC_PER_MSEC * 1000ULL / pipe->vrefresh;
+
+ r = sd_event_source_set_time(pipe->vsync_src, ts);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_ONESHOT);
+ if (r < 0)
+ goto error;
+
+ return;
+
+error:
+ log_debug("grdev: %s/%s/%s: cannot schedule vsync timer: %s",
+ pipe->card->session->name, pipe->card->name, pipe->name, strerror(-r));
}
/*