[PATCH 3/6] gl-renderer: Add support for a few YUV dmabuf formats

Emmanuel Gil Peyrot emmanuel.peyrot at collabora.com
Tue Nov 24 11:28:26 PST 2015


Namely the single-planar YUYV, the two-planar NV12, and the
three-planar YUV420, using the shaders already present in Weston.

Signed-off-by: Emmanuel Gil Peyrot <emmanuel.peyrot at collabora.com>

Maniphest Tasks: T13

Differential Revision: https://phabricator.freedesktop.org/D334
---
 src/gl-renderer.c | 280 +++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 237 insertions(+), 43 deletions(-)

diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 90e4842..cce93ee 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -101,11 +101,36 @@ struct egl_image {
 	int refcount;
 };
 
+enum import_type {
+	IMPORT_TYPE_INVALID,
+	IMPORT_TYPE_DIRECT,
+	IMPORT_TYPE_GL_CONVERSION
+};
+
 struct dmabuf_image {
 	struct linux_dmabuf_buffer *dmabuf;
 	int num_images;
 	struct egl_image *images[3];
 	struct wl_list link;
+
+	enum import_type import_type;
+	GLenum target;
+	struct gl_shader *shader;
+};
+
+struct yuv_plane_descriptor {
+	int width_divisor;
+	int height_divisor;
+	uint32_t format;
+	int plane_index;
+};
+
+struct yuv_format_descriptor {
+	uint32_t format;
+	int input_planes;
+	int output_planes;
+	int texture_type;
+	struct yuv_plane_descriptor plane[4];
 };
 
 struct gl_surface_state {
@@ -197,7 +222,7 @@ static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
 static inline const char *
 dump_format(uint32_t *format)
 {
-	// FIXME: this won’t work properly on big-endian.
+	/* FIXME: this won’t work properly on big-endian. */
 	return (const char *)format;
 }
 
@@ -1514,6 +1539,171 @@ import_simple_dmabuf(struct gl_renderer *gr,
 	return image;
 }
 
+struct yuv_format_descriptor yuv_formats[] = {
+	{
+		.format = DRM_FORMAT_YUYV,
+		.input_planes = 1,
+		.output_planes = 2,
+		.texture_type = EGL_TEXTURE_Y_XUXV_WL,
+		{{
+			.width_divisor = 1,
+			.height_divisor = 1,
+			.format = DRM_FORMAT_GR88,
+			.plane_index = 0
+		}, {
+			.width_divisor = 2,
+			.height_divisor = 1,
+			.format = DRM_FORMAT_ARGB8888,
+			.plane_index = 0
+		}}
+	}, {
+		.format = DRM_FORMAT_NV12,
+		.input_planes = 2,
+		.output_planes = 2,
+		.texture_type = EGL_TEXTURE_Y_UV_WL,
+		{{
+			.width_divisor = 1,
+			.height_divisor = 1,
+			.format = DRM_FORMAT_R8,
+			.plane_index = 0
+		}, {
+			.width_divisor = 2,
+			.height_divisor = 2,
+			.format = DRM_FORMAT_GR88,
+			.plane_index = 1
+		}}
+	}, {
+		.format = DRM_FORMAT_YUV420,
+		.input_planes = 3,
+		.output_planes = 3,
+		.texture_type = EGL_TEXTURE_Y_U_V_WL,
+		{{
+			.width_divisor = 1,
+			.height_divisor = 1,
+			.format = DRM_FORMAT_R8,
+			.plane_index = 0
+		}, {
+			.width_divisor = 2,
+			.height_divisor = 2,
+			.format = DRM_FORMAT_R8,
+			.plane_index = 1
+		}, {
+			.width_divisor = 2,
+			.height_divisor = 2,
+			.format = DRM_FORMAT_R8,
+			.plane_index = 2
+		}}
+	}
+};
+
+static struct egl_image *
+import_dmabuf_single_plane(struct gl_renderer *gr,
+                           const struct dmabuf_attributes *attributes,
+                           struct yuv_plane_descriptor *descriptor)
+{
+	struct dmabuf_attributes plane;
+	struct egl_image *image;
+
+	plane.width = attributes->width / descriptor->width_divisor;
+	plane.height = attributes->height / descriptor->height_divisor;
+	plane.format = descriptor->format;
+	plane.n_planes = 1;
+	plane.fd[0] = attributes->fd[descriptor->plane_index];
+	plane.offset[0] = attributes->offset[descriptor->plane_index];
+	plane.stride[0] = attributes->stride[descriptor->plane_index];
+	plane.modifier[0] = attributes->modifier[descriptor->plane_index];
+
+	image = import_simple_dmabuf(gr, &plane);
+	if (!image) {
+		weston_log("Failed to import plane %d as %.4s\n",
+		           descriptor->plane_index,
+		           dump_format(&descriptor->format));
+		return NULL;
+	}
+
+	return image;
+}
+
+static bool
+import_yuv_dmabuf(struct gl_renderer *gr,
+                  struct dmabuf_image *image)
+{
+	unsigned i;
+	int j;
+	int ret;
+	struct yuv_format_descriptor *format;
+	struct dmabuf_attributes *attributes = &image->dmabuf->attributes;
+
+	for (i = 0; i < ARRAY_LENGTH(yuv_formats); ++i) {
+		if (yuv_formats[i].format == attributes->format) {
+			format = &yuv_formats[i];
+			goto format_found;
+		}
+	}
+
+	weston_log("Error during import, and no known conversion for format "
+	           "%.4s in the renderer", dump_format(&attributes->format));
+	return false;
+
+format_found:
+	if (attributes->n_planes != format->input_planes) {
+		weston_log("%.4s dmabuf must contain %d plane%s (%d provided)",
+		           dump_format(&format->format),
+		           format->input_planes,
+		           (format->input_planes > 1) ? "s" : "",
+		           attributes->n_planes);
+		return false;
+	}
+
+	for (j = 0; j < format->output_planes; ++j) {
+		image->images[j] = import_dmabuf_single_plane(gr, attributes,
+		                                              &format->plane[j]);
+		if (!image->images[j]) {
+			while (j) {
+				ret = egl_image_unref(image->images[--j]);
+				assert(ret == 0);
+			}
+			return false;
+		}
+	}
+
+	image->num_images = format->output_planes;
+
+	switch (format->texture_type) {
+	case EGL_TEXTURE_Y_XUXV_WL:
+		image->shader = &gr->texture_shader_y_xuxv;
+		break;
+	case EGL_TEXTURE_Y_UV_WL:
+		image->shader = &gr->texture_shader_y_uv;
+		break;
+	case EGL_TEXTURE_Y_U_V_WL:
+		image->shader = &gr->texture_shader_y_u_v;
+		break;
+	default:
+		assert(false);
+	}
+
+	return true;
+}
+
+static GLenum
+choose_texture_target(struct dmabuf_attributes *attributes)
+{
+	if (attributes->n_planes > 1)
+		return GL_TEXTURE_EXTERNAL_OES;
+
+	switch (attributes->format & ~DRM_FORMAT_BIG_ENDIAN) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_AYUV:
+		return GL_TEXTURE_EXTERNAL_OES;
+	default:
+		return GL_TEXTURE_2D;
+	}
+}
+
 static struct dmabuf_image *
 import_dmabuf(struct gl_renderer *gr,
 	      struct linux_dmabuf_buffer *dmabuf)
@@ -1521,17 +1711,31 @@ import_dmabuf(struct gl_renderer *gr,
 	struct egl_image *egl_image;
 	struct dmabuf_image *image;
 
-	egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
-	if (!egl_image) {
-		weston_log("Format %.4s unsupported by EGL, aborting\n",
-		           dump_format(&dmabuf->attributes.format));
-		return NULL;
-	}
-
 	image = dmabuf_image_create();
 	image->dmabuf = dmabuf;
-	image->num_images = 1;
-	image->images[0] = egl_image;
+
+	egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
+	if (egl_image) {
+		image->num_images = 1;
+		image->images[0] = egl_image;
+		image->import_type = IMPORT_TYPE_DIRECT;
+		image->target = choose_texture_target(&dmabuf->attributes);
+
+		switch (image->target) {
+		case GL_TEXTURE_2D:
+			image->shader = &gr->texture_shader_rgba;
+			break;
+		default:
+			image->shader = &gr->texture_shader_egl_external;
+		}
+	} else {
+		if (!import_yuv_dmabuf(gr, image)) {
+			dmabuf_image_destroy(image);
+			return NULL;
+		}
+		image->import_type = IMPORT_TYPE_GL_CONVERSION;
+		image->target = GL_TEXTURE_2D;
+	}
 
 	return image;
 }
@@ -1567,22 +1771,28 @@ gl_renderer_import_dmabuf(struct weston_compositor *ec,
 	return true;
 }
 
-static GLenum
-choose_texture_target(struct dmabuf_attributes *attributes)
+static bool
+import_dmabuf2(struct gl_renderer *gr,
+               struct dmabuf_image *image)
 {
-	if (attributes->n_planes > 1)
-		return GL_TEXTURE_EXTERNAL_OES;
+	switch (image->import_type) {
+	case IMPORT_TYPE_DIRECT:
+		image->images[0] = import_simple_dmabuf(gr, &image->dmabuf->attributes);
+		if (!image->images[0])
+			return false;
+		break;
+
+	case IMPORT_TYPE_GL_CONVERSION:
+		if (!import_yuv_dmabuf(gr, image))
+			return false;
+		break;
 
-	switch (attributes->format & ~DRM_FORMAT_BIG_ENDIAN) {
-	case DRM_FORMAT_YUYV:
-	case DRM_FORMAT_YVYU:
-	case DRM_FORMAT_UYVY:
-	case DRM_FORMAT_VYUY:
-	case DRM_FORMAT_AYUV:
-		return GL_TEXTURE_EXTERNAL_OES;
 	default:
-		return GL_TEXTURE_2D;
+		weston_log("Invalid import type for dmabuf\n");
+		return false;
 	}
+
+	return true;
 }
 
 static void
@@ -1611,15 +1821,6 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
 		egl_image_unref(gs->images[i]);
 	gs->num_images = 0;
 
-	gs->target = choose_texture_target(&dmabuf->attributes);
-	switch (gs->target) {
-	case GL_TEXTURE_2D:
-		gs->shader = &gr->texture_shader_rgba;
-		break;
-	default:
-		gs->shader = &gr->texture_shader_egl_external;
-	}
-
 	/*
 	 * We try to always hold an imported EGLImage from the dmabuf
 	 * to prevent the client from preventing re-imports. But, we also
@@ -1638,24 +1839,16 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
 		assert(ret == 0);
 	}
 
-	for (i = 0; i < image->num_images; ++i) {
-		image->images[i] = import_simple_dmabuf(gr, &image->dmabuf->attributes);
-		if (!image->images[i]) {
-			image->num_images = 0;
-			while (i) {
-				ret = egl_image_unref(image->images[--i])
-				assert(ret == 0);
-			}
-			linux_dmabuf_buffer_send_server_error(dmabuf,
-							      "EGL dmabuf import failed");
-			return;
-		}
+	if (!import_dmabuf2(gr, image)) {
+		linux_dmabuf_buffer_send_server_error(dmabuf, "EGL dmabuf import failed");
+		return;
 	}
 
 	gs->num_images = image->num_images;
 	for (i = 0; i < gs->num_images; ++i)
 		gs->images[i] = egl_image_ref(image->images[i]);
 
+	gs->target = image->target;
 	ensure_textures(gs, gs->num_images);
 	for (i = 0; i < gs->num_images; ++i) {
 		glActiveTexture(GL_TEXTURE0 + i);
@@ -1663,6 +1856,7 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
 		gr->image_target_texture_2d(gs->target, gs->images[i]->image);
 	}
 
+	gs->shader = image->shader;
 	gs->pitch = buffer->width;
 	gs->height = buffer->height;
 	gs->buffer_type = BUFFER_TYPE_EGL;
-- 
2.6.2



More information about the wayland-devel mailing list