237 lines
8.2 KiB
Diff
237 lines
8.2 KiB
Diff
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 */
|