summaryrefslogtreecommitdiff
path: root/src/libsystemd-terminal/grdev-drm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-terminal/grdev-drm.c')
-rw-r--r--src/libsystemd-terminal/grdev-drm.c228
1 files changed, 129 insertions, 99 deletions
diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
index f0f0448635..00aac292d2 100644
--- a/src/libsystemd-terminal/grdev-drm.c
+++ b/src/libsystemd-terminal/grdev-drm.c
@@ -1083,15 +1083,136 @@ static void grdrm_crtc_expose(grdrm_crtc *crtc) {
grdev_pipe_ready(&crtc->pipe->base, true);
}
-static void grdrm_crtc_commit(grdrm_crtc *crtc) {
+static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) {
+ 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;
+ int r;
+
+ assert(crtc);
+ assert(slot);
+ assert(*slot);
+ assert(pipe);
+
+ 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;
+ set_crtc.x = 0;
+ set_crtc.y = 0;
+ set_crtc.mode_valid = 1;
+ set_crtc.mode = crtc->set.mode;
+
+ r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
+ if (r < 0) {
+ r = -errno;
+ log_debug("grdrm: %s: cannot set crtc %" PRIu32 ": %m",
+ card->base.name, crtc->object.id);
+
+ grdrm_card_async(card, r);
+ return;
+ }
+
+ if (!crtc->applied) {
+ log_debug("grdrm: %s: crtc %" PRIu32 " applied via deep modeset",
+ card->base.name, crtc->object.id);
+ crtc->applied = true;
+ }
+
+ *slot = NULL;
+ pipe->base.front = &fb->base;
+ fb->flipid = 0;
+ ++pipe->counter;
+ pipe->base.flipping = false;
+ pipe->base.flip = false;
+
+ 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) {
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);
+ uint32_t cnt;
+ size_t i;
+ int r;
+
+ assert(crtc);
+ assert(slot);
+ assert(*slot);
+ assert(pipe);
+
+ if (!crtc->applied && !grdrm_modes_compatible(&crtc->kern.mode, &crtc->set.mode))
+ return 0;
+
+ cnt = ++pipe->counter ? : ++pipe->counter;
+ page_flip.fb_id = fb->id;
+ page_flip.flags = DRM_MODE_PAGE_FLIP_EVENT;
+ page_flip.user_data = grdrm_encode_vblank_data(crtc->object.id, cnt);
+
+ r = ioctl(card->fd, DRM_IOCTL_MODE_PAGE_FLIP, &page_flip);
+ if (r < 0) {
+ r = -errno;
+ log_debug("grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m",
+ card->base.name, crtc->object.id);
+
+ if (grdrm_card_async(card, r))
+ return r;
+
+ return 0;
+ }
+
+ if (!crtc->applied) {
+ log_debug("grdrm: %s: crtc %" PRIu32 " applied via page flip",
+ card->base.name, crtc->object.id);
+ crtc->applied = true;
+ }
+
+ pipe->base.flipping = true;
+ pipe->base.flip = false;
+ pipe->counter = cnt;
+ fb->flipid = cnt;
+ *slot = NULL;
+
+ 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;
+}
+
+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;
- grdrm_fb *fb;
- uint32_t cnt;
- size_t i;
int r;
assert(crtc);
@@ -1141,102 +1262,11 @@ static void grdrm_crtc_commit(grdrm_crtc *crtc) {
if (!*slot)
return;
- fb = fb_from_base(*slot);
-
- if (crtc->applied || grdrm_modes_compatible(&crtc->kern.mode, &crtc->set.mode)) {
- cnt = ++pipe->counter ? : ++pipe->counter;
- page_flip.fb_id = fb->id;
- page_flip.flags = DRM_MODE_PAGE_FLIP_EVENT;
- page_flip.user_data = grdrm_encode_vblank_data(crtc->object.id, cnt);
-
- r = ioctl(card->fd, DRM_IOCTL_MODE_PAGE_FLIP, &page_flip);
- if (r < 0) {
- r = -errno;
- log_debug("grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m",
- card->base.name, crtc->object.id);
-
- if (grdrm_card_async(card, r))
- return;
-
- /* fall through to deep modeset */
- } else {
- if (!crtc->applied) {
- log_debug("grdrm: %s: crtc %" PRIu32 " applied via page flip",
- card->base.name, crtc->object.id);
- crtc->applied = true;
- }
-
- pipe->base.flipping = true;
- pipe->counter = cnt;
- fb->flipid = cnt;
- *slot = NULL;
-
- 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;
- }
- }
- }
- }
-
- if (!crtc->applied) {
- 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;
- set_crtc.x = 0;
- set_crtc.y = 0;
- set_crtc.mode_valid = 1;
- set_crtc.mode = crtc->set.mode;
-
- r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
- if (r < 0) {
- r = -errno;
- log_debug("grdrm: %s: cannot set crtc %" PRIu32 ": %m",
- card->base.name, crtc->object.id);
-
- grdrm_card_async(card, r);
- return;
- }
-
- if (!crtc->applied) {
- log_debug("grdrm: %s: crtc %" PRIu32 " applied via deep modeset",
- card->base.name, crtc->object.id);
- crtc->applied = true;
- }
-
- *slot = NULL;
- pipe->base.front = &fb->base;
- fb->flipid = 0;
- ++pipe->counter;
- pipe->base.flipping = false;
-
- 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;
- }
- }
+ r = grdrm_crtc_commit_flip(crtc, slot);
+ if (r == 0) {
+ /* in case we couldn't page-flip, perform deep modeset */
+ grdrm_crtc_commit_deep(crtc, slot);
}
-
- pipe->base.flip = false;
}
static void grdrm_crtc_restore(grdrm_crtc *crtc) {