[PATCH v2 weston 16/16] compositor-drm: Track currently-active view for planes
Daniel Stone
daniels at collabora.com
Mon Jun 22 09:25:21 PDT 2015
Track the view a plane is currently displaying, so we can avoid
needlessly recreating buffers.
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
src/compositor-drm.c | 123 +++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 104 insertions(+), 19 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index b3053c0..bb909b9 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -284,6 +284,9 @@ struct drm_plane {
enum wdrm_plane_type type;
+ struct weston_view *view;
+ struct wl_listener view_destroy;
+
struct drm_fb *current, *next;
struct drm_output *output;
struct drm_compositor *compositor;
@@ -1220,6 +1223,17 @@ drm_output_check_scanout_format(struct drm_output *output,
return 0;
}
+/**
+ * Try to use the primary DRM plane to directly display a full-screen view
+ *
+ * If a surface covers an entire output and is unoccluded, attempt to directly
+ * pageflip the primary DRM plane (not to be confused with the primary Weston
+ * plane) to the buffer. In legacy DRM usage, this will use drmModePageFlip;
+ * in atomic, this is just another plane.
+ *
+ * @param output Output to target
+ * @param ev View to prospectively use the primary plane
+ */
static struct weston_plane *
drm_output_prepare_scanout_view(struct drm_output *output,
struct weston_view *ev)
@@ -1920,6 +1934,7 @@ drm_output_prepare_overlay_view(struct drm_output *output,
struct drm_compositor *c = (struct drm_compositor *)ec;
struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
struct drm_plane *p;
+ struct drm_plane *cur = NULL;
int found = 0;
struct gbm_bo *bo;
pixman_region32_t dest_rect, src_rect;
@@ -1954,42 +1969,87 @@ drm_output_prepare_overlay_view(struct drm_output *output,
if (!drm_view_transform_supported(ev))
return NULL;
+ /* Find the current view this plane is assigned to, if any. */
+ wl_list_for_each(p, &c->plane_list, link) {
+ if (p->view != ev || p->output != output)
+ continue;
+
+ cur = p;
+ break;
+ }
+
+ bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
+ ev->surface->buffer_ref.buffer->resource,
+ GBM_BO_USE_SCANOUT);
+
wl_list_for_each(p, &c->plane_list, link) {
+ if (!bo)
+ continue;
+
if (!drm_plane_crtc_supported(output, p->possible_crtcs))
continue;
if (p->type != WDRM_PLANE_TYPE_OVERLAY)
continue;
- if (!p->next) {
+ format = drm_output_check_plane_format(p, ev, bo);
+ if (format == 0)
+ continue;
+
+ /* XXX: At this point, we need two runs through assign_planes;
+ * one to prepare any necessary views, and see if there
+ * are any currently-unused planes. This process may
+ * actually free up some planes for other views to use;
+ * if any planes have been freed up, we should do another
+ * pass to see if any planeless views can use any planes
+ * which have just been freed. But we want to cache what
+ * we can, so we're not, e.g., calling gbm_bo_import
+ * twice. */
+ if (!p->current && !p->next && !p->view) {
found = 1;
+ assert(p->output == NULL);
break;
}
- }
-
- /* No sprites available */
- if (!found)
- return NULL;
- bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
- ev->surface->buffer_ref.buffer->resource,
- GBM_BO_USE_SCANOUT);
- if (!bo)
- return NULL;
+ /* XXX: Factor out all the above to see if we can just use the
+ * current plane still. */
+ if (p == cur) {
+ found = 1;
+ break;
+ }
+ }
- format = drm_output_check_plane_format(p, ev, bo);
- if (format == 0) {
- gbm_bo_destroy(bo);
- return NULL;
+ /* If this buffer (view) was previously on a plane, but is being moved
+ * off, then get rid of it. */
+ if (cur && (!found || cur != p)) {
+ assert(cur->next == NULL);
+ cur->output = NULL;
+ wl_list_remove(&cur->view_destroy.link);
+ cur->view = NULL;
+ cur = NULL;
}
- p->next = drm_fb_get_from_bo(bo, c, format);
- if (!p->next) {
- gbm_bo_destroy(bo);
+ /* No planes available. */
+ if (!found) {
+ if (bo)
+ gbm_bo_destroy(bo);
return NULL;
}
- drm_fb_set_buffer(p->next, ev->surface->buffer_ref.buffer);
+ if (cur && cur->current &&
+ cur->current->buffer_ref.buffer == ev->surface->buffer_ref.buffer) {
+ p->next = p->current;
+ } else {
+ p->next = drm_fb_get_from_bo(bo, c, format);
+ if (!p->next) {
+ gbm_bo_destroy(bo);
+ return NULL;
+ }
+ drm_fb_set_buffer(p->next, ev->surface->buffer_ref.buffer);
+ }
+ p->output = output;
+ p->view = ev;
+ wl_signal_add(&ev->destroy_signal, &p->view_destroy);
box = pixman_region32_extents(&ev->transform.boundingbox);
p->base.x = box->x1;
@@ -2273,6 +2333,8 @@ drm_assign_planes(struct weston_output *output_base)
plane->next = NULL;
}
plane->output = NULL;
+ plane->view = NULL;
+ wl_list_remove(&plane->view_destroy.link);
next_plane = NULL;
}
}
@@ -3675,6 +3737,27 @@ err_free:
}
/**
+ * Handle destruction of a view active on a KMS plane
+ *
+ * Called when the weston_view currently being displayed on a KMS
+ * plane has been destroyed. The very act of destroying a view on
+ * an active plane will cause a repaint to be scheduled, but we
+ * still need to disable the plane itself.
+ *
+ * @param listener view_destroy listener struct from the plane
+ * @param data The view being destroyed
+ */
+static void
+drm_plane_view_destroyed(struct wl_listener *listener, void *data)
+{
+ struct drm_plane *plane =
+ container_of(listener, struct drm_plane, view_destroy);
+
+ assert(plane->view == data);
+ plane->view = NULL;
+}
+
+/**
* Create a drm_plane for a hardware plane
*
* Creates one drm_plane structure for a hardware plane, and initialises its
@@ -3700,6 +3783,7 @@ drm_plane_create(struct drm_compositor *ec, const drmModePlane *kplane)
return NULL;
}
+ weston_plane_init(&plane->base, &ec->base, 0, 0);
plane->possible_crtcs = kplane->possible_crtcs;
plane->plane_id = kplane->plane_id;
plane->current = NULL;
@@ -3707,6 +3791,7 @@ drm_plane_create(struct drm_compositor *ec, const drmModePlane *kplane)
plane->output = NULL;
plane->compositor = ec;
plane->count_formats = kplane->count_formats;
+ plane->view_destroy.notify = drm_plane_view_destroyed;
memcpy(plane->formats, kplane->formats,
kplane->count_formats * sizeof(kplane->formats[0]));
--
2.4.3
More information about the wayland-devel
mailing list