From aec3f44651998211d559b474bb830aad65680a62 Mon Sep 17 00:00:00 2001 From: David Herrmann 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 */