summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stone <daniels@collabora.com>2016-11-02 11:12:43 +0000
committerDaniel Stone <daniels@collabora.com>2017-02-07 19:16:31 +0000
commit99f860c2d7b78e50bdb8bf1194307fef3f79d894 (patch)
tree91caea7bc993648a2f05efc5a517d4ad24daaab3
parentfef7cb2e20daae342afbb4aa2ab71fc7a38c375d (diff)
compositor-drm: Introduce fb_last member
Clean up some ambiguity around current/next: current could previously have referred to a buffer which was being displayed, or the last buffer being displayed whilst we waited for a configuration we'd requested to take effect. Introduce a new variable, fb_last, which exclusively holds the latter case, thus leaving us with three unambiguous members: fb_pending is used as a scratch space for a buffer we're about to post, fb_current holds the buffer we last requested to display (whether active yet or not), and fb_last is again scratch space for a buffer which is no longer being displayed after a previous configuration reqeust. Signed-off-by: Daniel Stone <daniels@collabora.com> Differential Revision: https://phabricator.freedesktop.org/D1411
-rw-r--r--libweston/compositor-drm.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 3cbb1513..825e0afe 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -189,7 +189,7 @@ struct drm_output {
int current_cursor;
struct weston_plane fb_plane;
- struct drm_fb *fb_current, *fb_pending;
+ struct drm_fb *fb_current, *fb_pending, *fb_last;
struct backlight *backlight;
struct drm_fb *dumb[2];
@@ -210,7 +210,7 @@ struct drm_sprite {
struct weston_plane plane;
- struct drm_fb *fb_current, *fb_pending;
+ struct drm_fb *fb_current, *fb_pending, *fb_last;
struct drm_output *output;
struct drm_backend *backend;
@@ -755,6 +755,8 @@ drm_output_repaint(struct weston_output *output_base,
if (output->disable_pending || output->destroy_pending)
return -1;
+ assert(!output->fb_last);
+
drm_output_render(output, damage);
if (!output->fb_pending)
return -1;
@@ -780,6 +782,10 @@ drm_output_repaint(struct weston_output *output_base,
goto err_pageflip;
}
+ output->fb_last = output->fb_current;
+ output->fb_current = output->fb_pending;
+ output->fb_pending = NULL;
+
output->page_flip_pending = 1;
drm_output_set_cursor(output);
@@ -794,6 +800,8 @@ drm_output_repaint(struct weston_output *output_base,
.request.sequence = 1,
};
+ /* XXX: Set output much earlier, so we don't attempt to place
+ * planes on entirely the wrong output. */
if ((!s->fb_current && !s->fb_pending) ||
!drm_sprite_crtc_supported(output, s))
continue;
@@ -825,6 +833,9 @@ drm_output_repaint(struct weston_output *output_base,
}
s->output = output;
+ s->fb_last = s->fb_current;
+ s->fb_current = s->fb_pending;
+ s->fb_pending = NULL;
output->vblank_pending = 1;
}
@@ -934,9 +945,9 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
drm_output_update_msc(output, frame);
output->vblank_pending = 0;
- drm_fb_unref(s->fb_current);
- s->fb_current = s->fb_pending;
- s->fb_pending = NULL;
+ assert(s->fb_last || s->fb_current);
+ drm_fb_unref(s->fb_last);
+ s->fb_last = NULL;
if (!output->page_flip_pending) {
ts.tv_sec = sec;
@@ -964,9 +975,8 @@ page_flip_handler(int fd, unsigned int frame,
* we just want to page flip to the current buffer to get an accurate
* timestamp */
if (output->page_flip_pending) {
- drm_fb_unref(output->fb_current);
- output->fb_current = output->fb_pending;
- output->fb_pending = NULL;
+ drm_fb_unref(output->fb_last);
+ output->fb_last = NULL;
}
output->page_flip_pending = 0;
@@ -1496,10 +1506,16 @@ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mo
output->base.current_mode->flags =
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
- /* reset rendering stuff. */
+ /* XXX: This drops our current buffer too early, before we've started
+ * displaying it. Ideally this should be much more atomic and
+ * integrated with a full repaint cycle, rather than doing a
+ * sledgehammer modeswitch first, and only later showing new
+ * content.
+ */
drm_fb_unref(output->fb_current);
- drm_fb_unref(output->fb_pending);
- output->fb_current = output->fb_pending = NULL;
+ assert(!output->fb_last);
+ assert(!output->fb_pending);
+ output->fb_last = output->fb_current = NULL;
if (b->use_pixman) {
drm_output_fini_pixman(output);
@@ -2718,6 +2734,7 @@ create_sprites(struct drm_backend *b)
sprite->possible_crtcs = plane->possible_crtcs;
sprite->plane_id = plane->plane_id;
+ sprite->fb_last = NULL;
sprite->fb_current = NULL;
sprite->fb_pending = NULL;
sprite->backend = b;
@@ -2749,8 +2766,9 @@ destroy_sprites(struct drm_backend *backend)
sprite->plane_id,
output->crtc_id, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0);
+ drm_fb_unref(sprite->fb_last);
drm_fb_unref(sprite->fb_current);
- drm_fb_unref(sprite->fb_pending);
+ assert(!sprite->fb_pending);
weston_plane_release(&sprite->plane);
free(sprite);
}