Zbigniew Jędrzejewski-Szmek 62fe94
From 7b12a45b2dc6993e3f31642df2cc9b528294da40 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Sat, 20 Sep 2014 11:12:44 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] terminal: grdev: schedule virtual frame events if hw doesn't
Zbigniew Jędrzejewski-Szmek 62fe94
 support it
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Whenever we cannot use hardware frame events, we now schedule a virtual
Zbigniew Jędrzejewski-Szmek 62fe94
frame event to make sure applications don't have to do this. Usually,
Zbigniew Jędrzejewski-Szmek 62fe94
applications render only on data changes, but we can further reduce
Zbigniew Jędrzejewski-Szmek 62fe94
render-time by also limiting rendering to vsyncs.
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/grdev-drm.c      | 17 +++++++-
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/grdev-internal.h |  3 ++
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/grdev.c          | 69 +++++++++++++++++++++++++++-----
Zbigniew Jędrzejewski-Szmek 62fe94
 3 files changed, 79 insertions(+), 10 deletions(-)
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
Zbigniew Jędrzejewski-Szmek 62fe94
index 00aac292d2..3936a029fa 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/grdev-drm.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/grdev-drm.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -346,6 +346,8 @@ static bool grdrm_modes_compatible(const struct drm_mode_modeinfo *a, const stru
Zbigniew Jędrzejewski-Szmek 62fe94
                 return false;
Zbigniew Jędrzejewski-Szmek 62fe94
         if (a->vdisplay != b->vdisplay)
Zbigniew Jędrzejewski-Szmek 62fe94
                 return false;
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (a->vrefresh != b->vrefresh)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return false;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         return true;
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -1038,7 +1040,8 @@ static void grdrm_crtc_expose(grdrm_crtc *crtc) {
Zbigniew Jędrzejewski-Szmek 62fe94
         pipe = crtc->pipe;
Zbigniew Jędrzejewski-Szmek 62fe94
         if (pipe) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 if (pipe->base.width != crtc->set.mode.hdisplay ||
Zbigniew Jędrzejewski-Szmek 62fe94
-                    pipe->base.height != crtc->set.mode.vdisplay) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                    pipe->base.height != crtc->set.mode.vdisplay ||
Zbigniew Jędrzejewski-Szmek 62fe94
+                    pipe->base.vrefresh != crtc->set.mode.vrefresh) {
Zbigniew Jędrzejewski-Szmek 62fe94
                         grdev_pipe_free(&pipe->base);
Zbigniew Jędrzejewski-Szmek 62fe94
                         crtc->pipe = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
                         pipe = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -1127,6 +1130,12 @@ static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) {
Zbigniew Jędrzejewski-Szmek 62fe94
         pipe->base.flipping = false;
Zbigniew Jędrzejewski-Szmek 62fe94
         pipe->base.flip = false;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* We cannot schedule dummy page-flips on pipes, hence, the
Zbigniew Jędrzejewski-Szmek 62fe94
+         * application would have to schedule their own frame-timers.
Zbigniew Jędrzejewski-Szmek 62fe94
+         * To avoid duplicating that everywhere, we schedule our own
Zbigniew Jędrzejewski-Szmek 62fe94
+         * timer and raise a fake FRAME event when it fires. */
Zbigniew Jędrzejewski-Szmek 62fe94
+        grdev_pipe_schedule(&pipe->base, 1);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
         if (!pipe->base.back) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 for (i = 0; i < pipe->base.max_fbs; ++i) {
Zbigniew Jędrzejewski-Szmek 62fe94
                         if (!pipe->base.fbs[i])
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -1189,6 +1198,11 @@ static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) {
Zbigniew Jędrzejewski-Szmek 62fe94
         fb->flipid = cnt;
Zbigniew Jędrzejewski-Szmek 62fe94
         *slot = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* Raise fake FRAME event if it takes longer than 2
Zbigniew Jędrzejewski-Szmek 62fe94
+         * frames to receive the pageflip event. We assume the
Zbigniew Jędrzejewski-Szmek 62fe94
+         * queue ran over or some other error happened. */
Zbigniew Jędrzejewski-Szmek 62fe94
+        grdev_pipe_schedule(&pipe->base, 2);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
         if (!pipe->base.back) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 for (i = 0; i < pipe->base.max_fbs; ++i) {
Zbigniew Jędrzejewski-Szmek 62fe94
                         if (!pipe->base.fbs[i])
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -1501,6 +1515,7 @@ static int grdrm_pipe_new(grdrm_pipe **out, grdrm_crtc *crtc, struct drm_mode_mo
Zbigniew Jędrzejewski-Szmek 62fe94
         pipe->crtc = crtc;
Zbigniew Jędrzejewski-Szmek 62fe94
         pipe->base.width = mode->hdisplay;
Zbigniew Jędrzejewski-Szmek 62fe94
         pipe->base.height = mode->vdisplay;
Zbigniew Jędrzejewski-Szmek 62fe94
+        pipe->base.vrefresh = mode->vrefresh ? : 25;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         grdrm_pipe_name(name, crtc);
Zbigniew Jędrzejewski-Szmek 62fe94
         r = grdev_pipe_add(&pipe->base, name, n_fbs);
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
index 96830a714c..f5915b16e8 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/grdev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/grdev-internal.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -142,9 +142,11 @@ struct grdev_pipe {
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         grdev_tile *tile;
Zbigniew Jędrzejewski-Szmek 62fe94
         grdev_display_cache *cache;
Zbigniew Jędrzejewski-Szmek 62fe94
+        sd_event_source *vsync_src;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         uint32_t width;
Zbigniew Jędrzejewski-Szmek 62fe94
         uint32_t height;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t vrefresh;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         size_t max_fbs;
Zbigniew Jędrzejewski-Szmek 62fe94
         grdev_fb *front;
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -171,6 +173,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_pipe*, grdev_pipe_free);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 void grdev_pipe_ready(grdev_pipe *pipe, bool running);
Zbigniew Jędrzejewski-Szmek 62fe94
 void grdev_pipe_frame(grdev_pipe *pipe);
Zbigniew Jędrzejewski-Szmek 62fe94
+void grdev_pipe_schedule(grdev_pipe *pipe, uint64_t frames);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 /*
Zbigniew Jędrzejewski-Szmek 62fe94
  * Cards
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c
Zbigniew Jędrzejewski-Szmek 62fe94
index 397da1b205..43d0c7c9bf 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/grdev.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/grdev.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -574,6 +574,13 @@ grdev_pipe *grdev_find_pipe(grdev_card *card, const char *name) {
Zbigniew Jędrzejewski-Szmek 62fe94
         return hashmap_get(card->pipe_map, name);
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+static int pipe_vsync_fn(sd_event_source *src, uint64_t usec, void *userdata) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        grdev_pipe *pipe = userdata;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        grdev_pipe_frame(pipe);
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
 int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) {
Zbigniew Jędrzejewski-Szmek 62fe94
         int r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -585,6 +592,7 @@ int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) {
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(!pipe->cache, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(pipe->width > 0, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(pipe->height > 0, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(pipe->vrefresh > 0, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(!pipe->enabled, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(!pipe->running, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(name, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -605,6 +613,20 @@ int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) {
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
                 return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_add_time(pipe->card->session->context->event,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              &pipe->vsync_src,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              CLOCK_MONOTONIC,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              0,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              10 * USEC_PER_MSEC,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              pipe_vsync_fn,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              pipe);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_OFF);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
         r = hashmap_put(pipe->card->pipe_map, pipe->name, pipe);
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
                 return r;
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -633,6 +655,7 @@ grdev_pipe *grdev_pipe_free(grdev_pipe *pipe) {
Zbigniew Jędrzejewski-Szmek 62fe94
         tmp = *pipe;
Zbigniew Jędrzejewski-Szmek 62fe94
         pipe->vtable->free(pipe);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+        sd_event_source_unref(tmp.vsync_src);
Zbigniew Jędrzejewski-Szmek 62fe94
         grdev_tile_free(tmp.tile);
Zbigniew Jędrzejewski-Szmek 62fe94
         card_modified(tmp.card);
Zbigniew Jędrzejewski-Szmek 62fe94
         free(tmp.fbs);
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -676,17 +699,15 @@ void grdev_pipe_ready(grdev_pipe *pipe, bool running) {
Zbigniew Jędrzejewski-Szmek 62fe94
         pipe->running = running;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         /* runtime events for unused pipes are not interesting */
Zbigniew Jędrzejewski-Szmek 62fe94
-        if (pipe->cache) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (pipe->cache && pipe->enabled) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 grdev_display *display = pipe->tile->display;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                 assert(display);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-                if (running) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                        if (pipe->enabled)
Zbigniew Jędrzejewski-Szmek 62fe94
-                                session_frame(display->session, display);
Zbigniew Jędrzejewski-Szmek 62fe94
-                } else {
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (running)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        session_frame(display->session, display);
Zbigniew Jędrzejewski-Szmek 62fe94
+                else
Zbigniew Jędrzejewski-Szmek 62fe94
                         pipe->cache->incomplete = true;
Zbigniew Jędrzejewski-Szmek 62fe94
-                }
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -696,14 +717,44 @@ void grdev_pipe_frame(grdev_pipe *pipe) {
Zbigniew Jędrzejewski-Szmek 62fe94
         assert(pipe);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         /* if pipe is unused, ignore any frame events */
Zbigniew Jędrzejewski-Szmek 62fe94
-        if (!pipe->cache)
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!pipe->cache || !pipe->enabled)
Zbigniew Jędrzejewski-Szmek 62fe94
                 return;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         display = pipe->tile->display;
Zbigniew Jędrzejewski-Szmek 62fe94
         assert(display);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        if (pipe->enabled)
Zbigniew Jędrzejewski-Szmek 62fe94
-                session_frame(display->session, display);
Zbigniew Jędrzejewski-Szmek 62fe94
+        grdev_pipe_schedule(pipe, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+        session_frame(display->session, display);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+void grdev_pipe_schedule(grdev_pipe *pipe, uint64_t frames) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint64_t ts;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!frames) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_OFF);
Zbigniew Jędrzejewski-Szmek 62fe94
+                return;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_now(pipe->card->session->context->event, CLOCK_MONOTONIC, &ts);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        ts += frames * USEC_PER_MSEC * 1000ULL / pipe->vrefresh;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_source_set_time(pipe->vsync_src, ts);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_ONESHOT);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto error;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+error:
Zbigniew Jędrzejewski-Szmek 62fe94
+        log_debug("grdev: %s/%s/%s: cannot schedule vsync timer: %s",
Zbigniew Jędrzejewski-Szmek 62fe94
+                  pipe->card->session->name, pipe->card->name, pipe->name, strerror(-r));
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 /*