summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Gil Peyrot <emmanuel.peyrot@collabora.com>2016-01-11 19:04:35 +0000
committerDerek Foreman <derekf@osg.samsung.com>2016-01-11 13:30:01 -0600
commitbc35fdaed14563832c1f983181a9176909caef29 (patch)
treede7220846dfbeca86077a69b0b97faa68922c6d8
parentb8053505f40a1500edf942fdbfc0e66d1b7e9dff (diff)
downloadweston-bc35fdaed14563832c1f983181a9176909caef29.tar.gz
gl-renderer: Add support for a few YUV dmabuf formats
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@collabora.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> Maniphest Tasks: T13 Differential Revision: https://phabricator.freedesktop.org/D334
-rw-r--r--src/gl-renderer.c295
1 files changed, 252 insertions, 43 deletions
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index d4d92879..0ee20756 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 {
@@ -1517,25 +1542,219 @@ import_simple_dmabuf(struct gl_renderer *gr,
return image;
}
+/* The kernel header drm_fourcc.h defines the DRM formats below. We duplicate
+ * some of the definitions here so that building Weston won't require
+ * bleeding-edge kernel headers.
+ */
+#ifndef DRM_FORMAT_R8
+#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
+#endif
+
+#ifndef DRM_FORMAT_GR88
+#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
+#endif
+
+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;
+ char fmt[4];
+
+ 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, fmt));
+ 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 = NULL;
+ struct dmabuf_attributes *attributes = &image->dmabuf->attributes;
+ char fmt[4];
+
+ for (i = 0; i < ARRAY_LENGTH(yuv_formats); ++i) {
+ if (yuv_formats[i].format == attributes->format) {
+ format = &yuv_formats[i];
+ break;
+ }
+ }
+
+ if (!format) {
+ weston_log("Error during import, and no known conversion for format "
+ "%.4s in the renderer",
+ dump_format(attributes->format, fmt));
+ return false;
+ }
+
+ if (attributes->n_planes != format->input_planes) {
+ weston_log("%.4s dmabuf must contain %d plane%s (%d provided)",
+ dump_format(format->format, fmt),
+ 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)
{
struct egl_image *egl_image;
struct dmabuf_image *image;
- char fmt[4];
-
- 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, fmt));
- 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;
}
@@ -1571,22 +1790,28 @@ gl_renderer_import_dmabuf(struct weston_compositor *ec,
return true;
}
-static GLenum
-choose_texture_target(struct dmabuf_attributes *attributes)
+static bool
+import_known_dmabuf(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
@@ -1615,15 +1840,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
@@ -1642,24 +1858,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_known_dmabuf(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);
@@ -1667,6 +1875,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;