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 */