chiark / gitweb /
treewide: more log_*_errno() conversions, multiline calls
[elogind.git] / src / libsystemd-terminal / grdev.c
index 1e02a6799c56f60567b891396b0d41bb011eb8ec..db87ede762681666ad61bc4f5a838f9520249913 100644 (file)
@@ -54,10 +54,10 @@ static inline grdev_tile *tile_leftmost(grdev_tile *tile) {
 }
 
 #define TILE_FOREACH(_root, _i) \
-        for (_i = tile_leftmost(_root); _i; _i = tile_leftmost(_i->childs_by_node_next) ? : _i->parent)
+        for (_i = tile_leftmost(_root); _i; _i = tile_leftmost(_i->children_by_node_next) ? : _i->parent)
 
 #define TILE_FOREACH_SAFE(_root, _i, _next) \
-        for (_i = tile_leftmost(_root); _i && ((_next = tile_leftmost(_i->childs_by_node_next) ? : _i->parent), true); _i = _next)
+        for (_i = tile_leftmost(_root); _i && ((_next = tile_leftmost(_i->children_by_node_next) ? : _i->parent), true); _i = _next)
 
 static void tile_link(grdev_tile *tile, grdev_tile *parent) {
         grdev_display *display;
@@ -73,8 +73,8 @@ static void tile_link(grdev_tile *tile, grdev_tile *parent) {
 
         assert(!display || !display->enabled);
 
-        ++parent->node.n_childs;
-        LIST_PREPEND(childs_by_node, parent->node.child_list, tile);
+        ++parent->node.n_children;
+        LIST_PREPEND(children_by_node, parent->node.child_list, tile);
         tile->parent = parent;
 
         if (display) {
@@ -105,10 +105,10 @@ static void tile_unlink(grdev_tile *tile) {
 
         assert(parent->type == GRDEV_TILE_NODE);
         assert(parent->display == display);
-        assert(parent->node.n_childs > 0);
+        assert(parent->node.n_children > 0);
 
-        --parent->node.n_childs;
-        LIST_REMOVE(childs_by_node, parent->node.child_list, tile);
+        --parent->node.n_children;
+        LIST_REMOVE(children_by_node, parent->node.child_list, tile);
         tile->parent = NULL;
 
         if (display) {
@@ -127,14 +127,14 @@ static void tile_unlink(grdev_tile *tile) {
          * we must take care to not leave them around. Therefore, whenever we
          * unlink any part of a tree, we also destroy the parent, in case it's
          * now stale.
-         * Parents are stale if they have no childs and either have no display
+         * Parents are stale if they have no children and either have no display
          * or if they are intermediate nodes (i.e, they have a parent).
          * This means, you can easily create trees, but you can never partially
          * move or destruct them so far. They're always reduced to minimal form
          * if you cut them. This might change later, but so far we didn't need
          * partial destruction or the ability to move whole trees. */
 
-        if (parent->node.n_childs < 1 && (parent->parent || !parent->display))
+        if (parent->node.n_children < 1 && (parent->parent || !parent->display))
                 grdev_tile_free(parent);
 }
 
@@ -158,6 +158,7 @@ int grdev_tile_new_leaf(grdev_tile **out, grdev_pipe *pipe) {
         _cleanup_(grdev_tile_freep) grdev_tile *tile = NULL;
         int r;
 
+        assert_return(out, -EINVAL);
         assert_return(pipe, -EINVAL);
         assert_return(!pipe->tile, -EINVAL);
 
@@ -207,7 +208,7 @@ grdev_tile *grdev_tile_free(grdev_tile *tile) {
         case GRDEV_TILE_NODE:
                 assert(!tile->parent);
                 assert(!tile->display);
-                assert(tile->node.n_childs == 0);
+                assert(tile->node.n_children == 0);
 
                 break;
         }
@@ -282,6 +283,36 @@ grdev_display *grdev_display_free(grdev_display *display) {
         return NULL;
 }
 
+void grdev_display_set_userdata(grdev_display *display, void *userdata) {
+        assert(display);
+
+        display->userdata = userdata;
+}
+
+void *grdev_display_get_userdata(grdev_display *display) {
+        assert_return(display, NULL);
+
+        return display->userdata;
+}
+
+const char *grdev_display_get_name(grdev_display *display) {
+        assert_return(display, NULL);
+
+        return display->name;
+}
+
+uint32_t grdev_display_get_width(grdev_display *display) {
+        assert_return(display, 0);
+
+        return display->width;
+}
+
+uint32_t grdev_display_get_height(grdev_display *display) {
+        assert_return(display, 0);
+
+        return display->height;
+}
+
 bool grdev_display_is_enabled(grdev_display *display) {
         return display && display->enabled;
 }
@@ -312,7 +343,7 @@ void grdev_display_disable(grdev_display *display) {
         }
 }
 
-const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev, uint64_t minage) {
+const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev) {
         grdev_display_cache *cache;
         size_t idx;
 
@@ -327,7 +358,7 @@ const grdev_display_target *grdev_display_next_target(grdev_display *display, co
                 assert(cache->pipe->tile->display == display);
                 assert(display->pipes >= cache);
 
-                idx = (cache - display->pipes) / sizeof(*cache) + 1;
+                idx = cache - display->pipes + 1;
         } else {
                 idx = 0;
         }
@@ -343,52 +374,38 @@ const grdev_display_target *grdev_display_next_target(grdev_display *display, co
                 if (!pipe->running || !pipe->enabled)
                         continue;
 
-                /* if front-buffer is up-to-date, there's nothing to do */
-                if (minage > 0 && pipe->front && pipe->front->age >= minage)
-                        continue;
-
                 /* find suitable back-buffer */
-                if (!(fb = pipe->back)) {
-                        if (!pipe->vtable->target || !(fb = pipe->vtable->target(pipe)))
+                if (!pipe->back) {
+                        if (!pipe->vtable->target)
+                                continue;
+                        if (!(fb = pipe->vtable->target(pipe)))
                                 continue;
-                }
 
-                /* if back-buffer is up-to-date, schedule flip */
-                if (minage > 0 && fb->age >= minage) {
-                        grdev_display_flip_target(display, target, fb->age);
-                        continue;
+                        assert(fb == pipe->back);
                 }
 
-                /* we have an out-of-date back-buffer; return for redraw */
-                target->fb = fb;
+                target->front = pipe->front;
+                target->back = pipe->back;
+
                 return target;
         }
 
         return NULL;
 }
 
-void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target, uint64_t age) {
+void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target) {
         grdev_display_cache *cache;
-        size_t i;
 
         assert(display);
         assert(!display->modified);
         assert(display->enabled);
         assert(target);
-        assert(target->fb);
 
         cache = container_of(target, grdev_display_cache, target);
 
         assert(cache->pipe);
         assert(cache->pipe->tile->display == display);
 
-        /* reset age of all FB on overflow */
-        if (age < target->fb->age)
-                for (i = 0; i < cache->pipe->max_fbs; ++i)
-                        if (cache->pipe->fbs[i])
-                                cache->pipe->fbs[i]->age = 0;
-
-        ((grdev_fb*)target->fb)->age = age;
         cache->pipe->flip = true;
 }
 
@@ -454,10 +471,10 @@ static void display_cache_targets(grdev_display *display) {
 
         assert(display);
 
-        /* depth-first with childs before parent */
+        /* depth-first with children before parent */
         for (tile = tile_leftmost(display->tile);
              tile;
-             tile = tile_leftmost(tile->childs_by_node_next) ? : tile->parent) {
+             tile = tile_leftmost(tile->children_by_node_next) ? : tile->parent) {
                 if (tile->type == GRDEV_TILE_LEAF) {
                         grdev_pipe *p;
 
@@ -486,7 +503,7 @@ static void display_cache_targets(grdev_display *display) {
                 } else {
                         grdev_tile *child, *l;
 
-                        /* We're now at a node with all it's childs already
+                        /* We're now at a node with all its children already
                          * computed (depth-first, child before parent). We
                          * first need to know the size of our tile, then we
                          * recurse into all leafs and update their cache. */
@@ -494,7 +511,7 @@ static void display_cache_targets(grdev_display *display) {
                         tile->cache_w = 0;
                         tile->cache_h = 0;
 
-                        LIST_FOREACH(childs_by_node, child, tile->node.child_list) {
+                        LIST_FOREACH(children_by_node, child, tile->node.child_list) {
                                 if (child->x + child->cache_w > tile->cache_w)
                                         tile->cache_w = child->x + child->cache_w;
                                 if (child->y + child->cache_h > tile->cache_h)
@@ -553,13 +570,15 @@ static bool display_cache(grdev_display *display) {
         }
 
         display_cache_targets(display);
+        display->width = display->tile->cache_w;
+        display->height = display->tile->cache_h;
 
         r = 0;
 
 out:
         if (r < 0)
-                log_debug("grdev: %s/%s: cannot cache pipes: %s",
-                          display->session->name, display->name, strerror(-r));
+                log_debug_errno(r, "grdev: %s/%s: cannot cache pipes: %m",
+                                display->session->name, display->name);
         return true;
 }
 
@@ -574,6 +593,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 +611,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 +632,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 +674,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 +718,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 +736,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_errno(r, "grdev: %s/%s/%s: cannot schedule vsync timer: %m",
+                        pipe->card->session->name, pipe->card->name, pipe->name);
 }
 
 /*
@@ -921,14 +991,17 @@ static void session_change_display(grdev_session *session, grdev_display *displa
 
         changed = display_cache(display);
 
-        if (display->n_leafs == 0)
+        if (display->n_leafs == 0) {
                 session_remove_display(session, display);
-        else if (!display->public)
+        } else if (!display->public) {
                 session_add_display(session, display);
-        else if (changed)
+                session_frame(session, display);
+        } else if (changed) {
                 session_raise_display_change(session, display);
-        else if (display->framed)
                 session_frame(session, display);
+        } else if (display->framed) {
+                session_frame(session, display);
+        }
 }
 
 static void session_frame(grdev_session *session, grdev_display *display) {
@@ -1095,7 +1168,7 @@ void grdev_session_add_drm(grdev_session *session, struct udev_device *ud) {
 
         devnum = udev_device_get_devnum(ud);
         if (devnum == 0)
-                return;
+                return grdev_session_hotplug_drm(session, ud);
 
         card = grdev_find_drm_card(session, devnum);
         if (card)
@@ -1103,8 +1176,8 @@ void grdev_session_add_drm(grdev_session *session, struct udev_device *ud) {
 
         r = grdev_drm_card_new(&card, session, ud);
         if (r < 0) {
-                log_debug("grdev: %s: cannot add DRM device for %s: %s",
-                          session->name, udev_device_get_syspath(ud), strerror(-r));
+                log_debug_errno(r, "grdev: %s: cannot add DRM device for %s: %m",
+                                session->name, udev_device_get_syspath(ud));
                 return;
         }
 
@@ -1120,7 +1193,7 @@ void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud) {
 
         devnum = udev_device_get_devnum(ud);
         if (devnum == 0)
-                return;
+                return grdev_session_hotplug_drm(session, ud);
 
         card = grdev_find_drm_card(session, devnum);
         if (!card)
@@ -1130,21 +1203,27 @@ void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud) {
 }
 
 void grdev_session_hotplug_drm(grdev_session *session, struct udev_device *ud) {
-        grdev_card *card;
+        grdev_card *card = NULL;
+        struct udev_device *p;
         dev_t devnum;
 
         assert(session);
         assert(ud);
 
-        devnum = udev_device_get_devnum(ud);
-        if (devnum == 0)
-                return;
+        for (p = ud; p; p = udev_device_get_parent_with_subsystem_devtype(p, "drm", NULL)) {
+                devnum = udev_device_get_devnum(ud);
+                if (devnum == 0)
+                        continue;
+
+                card = grdev_find_drm_card(session, devnum);
+                if (card)
+                        break;
+        }
 
-        card = grdev_find_drm_card(session, devnum);
         if (!card)
                 return;
 
-        /* TODO: hotplug card */
+        grdev_drm_card_hotplug(card, ud);
 }
 
 static void session_configure(grdev_session *session) {
@@ -1190,8 +1269,8 @@ static void session_configure(grdev_session *session) {
                         } else if (!display) {
                                 r = grdev_display_new(&display, session, pipe->name);
                                 if (r < 0) {
-                                        log_debug("grdev: %s/%s: cannot create display for pipe %s: %s",
-                                                  session->name, card->name, pipe->name, strerror(-r));
+                                        log_debug_errno(r, "grdev: %s/%s: cannot create display for pipe %s: %m",
+                                                        session->name, card->name, pipe->name);
                                         continue;
                                 }
                         }