[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