compositor-drm: Extract overlay FB import to helper

... in order to be able to use it from scanout as well.

In doing this, the check for format compatibility is moved from after
selecting a plane to before selecting a plane. If different planes have
disjoint format support, this ensures that we don't reject the view from
all overlay consideration, just because the first plane we found didn't
support its format.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Tested-by: Emre Ucan <eucan@de.adit-jv.com>
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index c8ee84d..0ecfc90 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -1305,6 +1305,109 @@
 	return true;
 }
 
+static bool
+drm_view_is_opaque(struct weston_view *ev)
+{
+	pixman_region32_t r;
+	bool ret = false;
+
+	pixman_region32_init_rect(&r, 0, 0,
+				  ev->surface->width,
+				  ev->surface->height);
+	pixman_region32_subtract(&r, &r, &ev->surface->opaque);
+
+	if (!pixman_region32_not_empty(&r))
+		ret = true;
+
+	pixman_region32_fini(&r);
+
+	return ret;
+}
+
+static struct drm_fb *
+drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
+{
+	struct drm_output *output = state->output;
+	struct drm_backend *b = to_drm_backend(output->base.compositor);
+	struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+	struct linux_dmabuf_buffer *dmabuf;
+	struct drm_fb *fb;
+	struct gbm_bo *bo;
+
+	/* Don't import buffers which span multiple outputs. */
+	if (ev->output_mask != (1u << output->base.id))
+		return NULL;
+
+	if (ev->alpha != 1.0f)
+		return NULL;
+
+	if (!drm_view_transform_supported(ev, &output->base))
+		return NULL;
+
+	if (!buffer)
+		return NULL;
+
+	if (wl_shm_buffer_get(buffer->resource))
+		return NULL;
+
+	if (!b->gbm)
+		return NULL;
+
+	dmabuf = linux_dmabuf_buffer_get(buffer->resource);
+	if (dmabuf) {
+#ifdef HAVE_GBM_FD_IMPORT
+		/* XXX: TODO:
+		 *
+		 * Use AddFB2 directly, do not go via GBM.
+		 * Add support for multiplanar formats.
+		 * Both require refactoring in the DRM-backend to
+		 * support a mix of gbm_bos and drmfbs.
+		 */
+		 struct gbm_import_fd_data gbm_dmabuf = {
+			 .fd = dmabuf->attributes.fd[0],
+			 .width = dmabuf->attributes.width,
+			 .height = dmabuf->attributes.height,
+			 .stride = dmabuf->attributes.stride[0],
+			 .format = dmabuf->attributes.format
+		 };
+
+                /* XXX: TODO:
+                 *
+                 * Currently the buffer is rejected if any dmabuf attribute
+                 * flag is set.  This keeps us from passing an inverted /
+                 * interlaced / bottom-first buffer (or any other type that may
+                 * be added in the future) through to an overlay.  Ultimately,
+                 * these types of buffers should be handled through buffer
+                 * transforms and not as spot-checks requiring specific
+                 * knowledge. */
+		if (dmabuf->attributes.n_planes != 1 ||
+                    dmabuf->attributes.offset[0] != 0 ||
+		    dmabuf->attributes.flags)
+			return NULL;
+
+		bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
+				   GBM_BO_USE_SCANOUT);
+#else
+		return NULL;
+#endif
+	} else {
+		bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
+				   buffer->resource, GBM_BO_USE_SCANOUT);
+	}
+
+	if (!bo)
+		return NULL;
+
+	fb = drm_fb_get_from_bo(bo, b, drm_view_is_opaque(ev), BUFFER_CLIENT);
+	if (!fb) {
+		gbm_bo_destroy(bo);
+		return NULL;
+	}
+
+	drm_fb_set_buffer(fb, buffer);
+	return fb;
+}
+
 /**
  * Return a plane state from a drm_output_state.
  */
@@ -1642,25 +1745,6 @@
 	}
 }
 
-static bool
-drm_view_is_opaque(struct weston_view *ev)
-{
-	pixman_region32_t r;
-	bool ret = false;
-
-	pixman_region32_init_rect(&r, 0, 0,
-				  ev->surface->width,
-				  ev->surface->height);
-	pixman_region32_subtract(&r, &r, &ev->surface->opaque);
-
-	if (!pixman_region32_not_empty(&r))
-		ret = true;
-
-	pixman_region32_fini(&r);
-
-	return ret;
-}
-
 static struct weston_plane *
 drm_output_prepare_scanout_view(struct drm_output_state *output_state,
 				struct weston_view *ev)
@@ -2749,31 +2833,16 @@
 	struct drm_output *output = output_state->output;
 	struct weston_compositor *ec = output->base.compositor;
 	struct drm_backend *b = to_drm_backend(ec);
-	struct wl_resource *buffer_resource;
 	struct drm_plane *p;
 	struct drm_plane_state *state = NULL;
-	struct linux_dmabuf_buffer *dmabuf;
-	struct gbm_bo *bo = NULL;
+	struct drm_fb *fb;
 	unsigned int i;
 
 	if (b->sprites_are_broken)
 		return NULL;
 
-	/* Don't import buffers which span multiple outputs. */
-	if (ev->output_mask != (1u << output->base.id))
-		return NULL;
-
-	/* We can only import GBM buffers. */
-	if (b->gbm == NULL)
-		return NULL;
-
-	if (ev->surface->buffer_ref.buffer == NULL)
-		return NULL;
-	buffer_resource = ev->surface->buffer_ref.buffer->resource;
-	if (wl_shm_buffer_get(buffer_resource))
-		return NULL;
-
-	if (ev->alpha != 1.0f)
+	fb = drm_fb_get_from_view(output_state, ev);
+	if (!fb)
 		return NULL;
 
 	wl_list_for_each(p, &b->plane_list, link) {
@@ -2783,6 +2852,14 @@
 		if (!drm_plane_is_available(p, output))
 			continue;
 
+		/* Check whether the format is supported */
+		for (i = 0; i < p->count_formats; i++) {
+			if (p->formats[i] == fb->format->format)
+				break;
+		}
+		if (i == p->count_formats)
+			continue;
+
 		state = drm_output_state_get_plane(output_state, p);
 		if (state->fb) {
 			state = NULL;
@@ -2793,10 +2870,14 @@
 	}
 
 	/* No sprites available */
-	if (!state)
+	if (!state) {
+		drm_fb_unref(fb);
 		return NULL;
+	}
 
+	state->fb = fb;
 	state->output = output;
+
 	if (!drm_plane_state_coords_for_view(state, ev))
 		goto err;
 
@@ -2804,71 +2885,9 @@
 	    state->src_h != state->dest_h << 16)
 		goto err;
 
-	if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
-#ifdef HAVE_GBM_FD_IMPORT
-		/* XXX: TODO:
-		 *
-		 * Use AddFB2 directly, do not go via GBM.
-		 * Add support for multiplanar formats.
-		 * Both require refactoring in the DRM-backend to
-		 * support a mix of gbm_bos and drmfbs.
-		 */
-		struct gbm_import_fd_data gbm_dmabuf = {
-			.fd     = dmabuf->attributes.fd[0],
-			.width  = dmabuf->attributes.width,
-			.height = dmabuf->attributes.height,
-			.stride = dmabuf->attributes.stride[0],
-			.format = dmabuf->attributes.format
-		};
-
-                /* XXX: TODO:
-                 *
-                 * Currently the buffer is rejected if any dmabuf attribute
-                 * flag is set.  This keeps us from passing an inverted /
-                 * interlaced / bottom-first buffer (or any other type that may
-                 * be added in the future) through to an overlay.  Ultimately,
-                 * these types of buffers should be handled through buffer
-                 * transforms and not as spot-checks requiring specific
-                 * knowledge. */
-		if (dmabuf->attributes.n_planes != 1 ||
-                    dmabuf->attributes.offset[0] != 0 ||
-		    dmabuf->attributes.flags)
-			goto err;
-
-		bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
-				   GBM_BO_USE_SCANOUT);
-#else
-		goto err;
-#endif
-	} else {
-		bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
-				   buffer_resource, GBM_BO_USE_SCANOUT);
-	}
-	if (!bo)
-		goto err;
-
-	state->fb = drm_fb_get_from_bo(bo, b, drm_view_is_opaque(ev),
-				       BUFFER_CLIENT);
-	if (!state->fb)
-		goto err;
-	bo = NULL;
-
-	/* Check whether the format is supported */
-	for (i = 0; i < p->count_formats; i++)
-		if (p->formats[i] == state->fb->format->format)
-			break;
-	if (i == p->count_formats)
-		goto err;
-
-	drm_fb_set_buffer(state->fb, ev->surface->buffer_ref.buffer);
-
 	return &p->base;
 
 err:
-	/* Destroy the BO as we've allocated it, but it won't yet
-	 * be deallocated by the state. */
-	if (bo)
-		gbm_bo_destroy(bo);
 	drm_plane_state_put_back(state);
 	return NULL;
 }