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.
This commit is contained in:
David Herrmann 2014-10-02 17:59:26 +02:00
parent 6a15ce2b3e
commit aec3f44651
2 changed files with 44 additions and 56 deletions

View file

@ -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,
};
/*

View file

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