Blob Blame History Raw
From aec3f44651998211d559b474bb830aad65680a62 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 2 Oct 2014 17:59:26 +0200
Subject: [PATCH] terminal/drm: provide pipe->target() callback

Instead of looking for available back-buffers on each operation, set it to
NULL and wait for the next frame request. It will call back into the pipe
to request the back-buffer via ->target(), where we can do the same and
look for an available backbuffer.

This simplifies the code and avoids double lookups if we run short of
buffers.
---
 src/libsystemd-terminal/grdev-drm.c | 98 ++++++++++++++++---------------------
 src/libsystemd-terminal/grdev.c     |  2 +
 2 files changed, 44 insertions(+), 56 deletions(-)

diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
index 6b130116d7..57b930bc0f 100644
--- a/src/libsystemd-terminal/grdev-drm.c
+++ b/src/libsystemd-terminal/grdev-drm.c
@@ -1095,19 +1095,19 @@ static void grdrm_crtc_expose(grdrm_crtc *crtc) {
         grdev_pipe_ready(&crtc->pipe->base, true);
 }
 
-static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) {
+static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb *basefb) {
         struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id };
         grdrm_card *card = crtc->object.card;
         grdrm_pipe *pipe = crtc->pipe;
-        grdrm_fb *fb = fb_from_base(*slot);
-        size_t i;
+        grdrm_fb *fb;
         int r;
 
         assert(crtc);
-        assert(slot);
-        assert(*slot);
+        assert(basefb);
         assert(pipe);
 
+        fb = fb_from_base(basefb);
+
         set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->set.connectors);
         set_crtc.count_connectors = crtc->set.n_connectors;
         set_crtc.fb_id = fb->id;
@@ -1132,7 +1132,7 @@ static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) {
                 crtc->applied = true;
         }
 
-        *slot = NULL;
+        pipe->base.back = NULL;
         pipe->base.front = &fb->base;
         fb->flipid = 0;
         ++pipe->counter;
@@ -1144,40 +1144,25 @@ static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) {
          * To avoid duplicating that everywhere, we schedule our own
          * timer and raise a fake FRAME event when it fires. */
         grdev_pipe_schedule(&pipe->base, 1);
-
-        if (!pipe->base.back) {
-                for (i = 0; i < pipe->base.max_fbs; ++i) {
-                        if (!pipe->base.fbs[i])
-                                continue;
-
-                        fb = fb_from_base(pipe->base.fbs[i]);
-                        if (&fb->base == pipe->base.front)
-                                continue;
-
-                        fb->flipid = 0;
-                        pipe->base.back = &fb->base;
-                        break;
-                }
-        }
 }
 
-static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) {
+static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb *basefb) {
         struct drm_mode_crtc_page_flip page_flip = { .crtc_id = crtc->object.id };
         grdrm_card *card = crtc->object.card;
         grdrm_pipe *pipe = crtc->pipe;
-        grdrm_fb *fb = fb_from_base(*slot);
+        grdrm_fb *fb;
         uint32_t cnt;
-        size_t i;
         int r;
 
         assert(crtc);
-        assert(slot);
-        assert(*slot);
+        assert(basefb);
         assert(pipe);
 
         if (!crtc->applied && !grdrm_modes_compatible(&crtc->kern.mode, &crtc->set.mode))
                 return 0;
 
+        fb = fb_from_base(basefb);
+
         cnt = ++pipe->counter ? : ++pipe->counter;
         page_flip.fb_id = fb->id;
         page_flip.flags = DRM_MODE_PAGE_FLIP_EVENT;
@@ -1209,29 +1194,13 @@ static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) {
         pipe->base.flip = false;
         pipe->counter = cnt;
         fb->flipid = cnt;
-        *slot = NULL;
+        pipe->base.back = NULL;
 
         /* Raise fake FRAME event if it takes longer than 2
          * frames to receive the pageflip event. We assume the
          * queue ran over or some other error happened. */
         grdev_pipe_schedule(&pipe->base, 2);
 
-        if (!pipe->base.back) {
-                for (i = 0; i < pipe->base.max_fbs; ++i) {
-                        if (!pipe->base.fbs[i])
-                                continue;
-
-                        fb = fb_from_base(pipe->base.fbs[i]);
-                        if (&fb->base == pipe->base.front)
-                                continue;
-                        if (fb->flipid)
-                                continue;
-
-                        pipe->base.back = &fb->base;
-                        break;
-                }
-        }
-
         return 1;
 }
 
@@ -1239,7 +1208,7 @@ static void grdrm_crtc_commit(grdrm_crtc *crtc) {
         struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id };
         grdrm_card *card = crtc->object.card;
         grdrm_pipe *pipe;
-        grdev_fb **slot;
+        grdev_fb *fb;
         int r;
 
         assert(crtc);
@@ -1280,19 +1249,19 @@ static void grdrm_crtc_commit(grdrm_crtc *crtc) {
         assert(crtc->set.n_connectors > 0);
 
         if (pipe->base.flip)
-                slot = &pipe->base.back;
+                fb = pipe->base.back;
         else if (!crtc->applied)
-                slot = &pipe->base.front;
+                fb = pipe->base.front;
         else
                 return;
 
-        if (!*slot)
+        if (!fb)
                 return;
 
-        r = grdrm_crtc_commit_flip(crtc, slot);
+        r = grdrm_crtc_commit_flip(crtc, fb);
         if (r == 0) {
                 /* in case we couldn't page-flip, perform deep modeset */
-                grdrm_crtc_commit_deep(crtc, slot);
+                grdrm_crtc_commit_deep(crtc, fb);
         }
 }
 
@@ -1335,7 +1304,6 @@ static void grdrm_crtc_restore(grdrm_crtc *crtc) {
 static void grdrm_crtc_flip_complete(grdrm_crtc *crtc, uint32_t counter, struct drm_event_vblank *event) {
         bool flipped = false;
         grdrm_pipe *pipe;
-        grdrm_fb *back = NULL;
         size_t i;
 
         assert(crtc);
@@ -1366,15 +1334,9 @@ static void grdrm_crtc_flip_complete(grdrm_crtc *crtc, uint32_t counter, struct
                         flipped = true;
                 } else if (counter - fb->flipid < UINT16_MAX) {
                         fb->flipid = 0;
-                        back = fb;
-                } else if (fb->flipid == 0) {
-                        back = fb;
                 }
         }
 
-        if (!pipe->base.back && back)
-                pipe->base.back = &back->base;
-
         if (flipped) {
                 crtc->pipe->base.flipping = false;
                 grdev_pipe_frame(&pipe->base);
@@ -1561,8 +1523,32 @@ static void grdrm_pipe_free(grdev_pipe *basepipe) {
         free(pipe);
 }
 
+static grdev_fb *grdrm_pipe_target(grdev_pipe *basepipe) {
+        grdrm_fb *fb;
+        size_t i;
+
+        if (!basepipe->back) {
+                for (i = 0; i < basepipe->max_fbs; ++i) {
+                        if (!basepipe->fbs[i])
+                                continue;
+
+                        fb = fb_from_base(basepipe->fbs[i]);
+                        if (&fb->base == basepipe->front)
+                                continue;
+                        if (basepipe->flipping && fb->flipid)
+                                continue;
+
+                        basepipe->back = &fb->base;
+                        break;
+                }
+        }
+
+        return basepipe->back;
+}
+
 static const grdev_pipe_vtable grdrm_pipe_vtable = {
         .free                   = grdrm_pipe_free,
+        .target                 = grdrm_pipe_target,
 };
 
 /*
diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c
index aaac06ec34..bbc45afad4 100644
--- a/src/libsystemd-terminal/grdev.c
+++ b/src/libsystemd-terminal/grdev.c
@@ -382,6 +382,8 @@ const grdev_display_target *grdev_display_next_target(grdev_display *display, co
                 if (!(fb = pipe->back)) {
                         if (!pipe->vtable->target || !(fb = pipe->vtable->target(pipe)))
                                 continue;
+
+                        assert(fb == pipe->back);
                 }
 
                 /* if back-buffer is up-to-date, schedule flip */