wayland/dma-buf: Add support for YUV formats

Implement importing of multi-plane formats. For now, only support
importing planes individually using "sub-formats". This is the most
commonly driver-supported approach in the moment, used by other
Wayland compositors as well.

In the future we will additionally want to support importing the formats
directly and let the drivers handle conversion internally.

Co-Authored-By: Robert Mader <robert.mader@collabora.com>
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2191>
This commit is contained in:
Niels De Graef 2021-02-15 19:06:37 +01:00 committed by Marge Bot
parent b15e14e027
commit 239912cc1f

View File

@ -51,6 +51,7 @@
#include "cogl/cogl-egl.h"
#include "cogl/cogl.h"
#include "common/meta-cogl-drm-formats.h"
#include "compositor/meta-multi-texture-format-private.h"
#include "meta/meta-backend.h"
#include "wayland/meta-wayland-buffer.h"
#include "wayland/meta-wayland-private.h"
@ -343,12 +344,8 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
MetaWaylandDmaBufBuffer *dma_buf = buffer->dma_buf.dma_buf;
uint32_t n_planes;
uint64_t modifiers[META_WAYLAND_DMA_BUF_MAX_FDS];
MetaMultiTextureFormat multi_format;
CoglPixelFormat cogl_format;
EGLImageKHR egl_image;
CoglEglImageFlags flags;
CoglTexture2D *cogl_texture;
#ifdef HAVE_NATIVE_BACKEND
MetaDrmFormatBuf format_buf;
#endif
@ -358,7 +355,7 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
if (!meta_cogl_pixel_format_from_drm_format (dma_buf->drm_format,
&cogl_format,
NULL))
&multi_format))
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
@ -368,49 +365,140 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
#ifdef HAVE_NATIVE_BACKEND
meta_topic (META_DEBUG_WAYLAND,
"[dma-buf] wl_buffer@%u DRM format %s -> CoglPixelFormat %s",
"[dma-buf] wl_buffer@%u DRM format %s "
"-> MetaMultiTextureFormat %s / CoglPixelFormat %s",
wl_resource_get_id (meta_wayland_buffer_get_resource (buffer)),
meta_drm_format_to_string (&format_buf, dma_buf->drm_format),
meta_multi_texture_format_to_string (multi_format),
cogl_pixel_format_to_string (cogl_format));
#endif
for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++)
if (multi_format == META_MULTI_TEXTURE_FORMAT_SIMPLE)
{
if (dma_buf->fds[n_planes] < 0)
break;
EGLImageKHR egl_image;
CoglEglImageFlags flags;
CoglTexture2D *cogl_texture;
uint64_t modifiers[META_WAYLAND_DMA_BUF_MAX_FDS];
uint32_t n_planes;
modifiers[n_planes] = dma_buf->drm_modifier;
for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++)
{
if (dma_buf->fds[n_planes] < 0)
break;
modifiers[n_planes] = dma_buf->drm_modifier;
}
egl_image = meta_egl_create_dmabuf_image (egl,
egl_display,
dma_buf->width,
dma_buf->height,
dma_buf->drm_format,
n_planes,
dma_buf->fds,
dma_buf->strides,
dma_buf->offsets,
modifiers,
error);
if (egl_image == EGL_NO_IMAGE_KHR)
return FALSE;
flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
cogl_texture = cogl_egl_texture_2d_new_from_image (cogl_context,
dma_buf->width,
dma_buf->height,
cogl_format,
egl_image,
flags,
error);
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
if (!cogl_texture)
return FALSE;
buffer->dma_buf.texture =
meta_multi_texture_new_simple (COGL_TEXTURE (cogl_texture));
}
else
{
CoglTexture **textures;
g_autoptr (GPtrArray) planes = NULL;
CoglPixelFormat subformats[META_WAYLAND_DMA_BUF_MAX_FDS];
uint8_t horizontal_factors[META_WAYLAND_DMA_BUF_MAX_FDS];
uint8_t vertical_factors[META_WAYLAND_DMA_BUF_MAX_FDS];
uint8_t plane_indices[META_WAYLAND_DMA_BUF_MAX_FDS];
int n_planes, i;
egl_image = meta_egl_create_dmabuf_image (egl,
egl_display,
dma_buf->width,
dma_buf->height,
dma_buf->drm_format,
n_planes,
dma_buf->fds,
dma_buf->strides,
dma_buf->offsets,
modifiers,
error);
if (egl_image == EGL_NO_IMAGE_KHR)
return FALSE;
n_planes = meta_multi_texture_format_get_n_planes (multi_format);
flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
cogl_texture = cogl_egl_texture_2d_new_from_image (cogl_context,
dma_buf->width,
dma_buf->height,
cogl_format,
egl_image,
flags,
error);
/* Each EGLImage is a plane in the final CoglMultiPlaneTexture */
planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
meta_multi_texture_format_get_subformats (multi_format, subformats);
meta_multi_texture_format_get_plane_indices (multi_format, plane_indices);
meta_multi_texture_format_get_subsampling_factors (multi_format,
horizontal_factors,
vertical_factors);
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
for (i = 0; i < n_planes; i++)
{
EGLImageKHR egl_image;
CoglEglImageFlags flags;
CoglTexture2D *cogl_texture;
uint32_t drm_format = 0;
int plane_index, j;
if (!cogl_texture)
return FALSE;
for (j = 0; j < G_N_ELEMENTS (meta_cogl_drm_format_map); j++)
{
if (meta_cogl_drm_format_map[j].cogl_format == subformats[i])
{
drm_format = meta_cogl_drm_format_map[j].drm_format;
break;
}
}
g_return_val_if_fail (drm_format != 0, FALSE);
buffer->dma_buf.texture = meta_multi_texture_new_simple (COGL_TEXTURE (cogl_texture));
plane_index = plane_indices[i];
egl_image = meta_egl_create_dmabuf_image (egl,
egl_display,
dma_buf->width /
horizontal_factors[i],
dma_buf->height /
vertical_factors[i],
drm_format,
1,
&dma_buf->fds[plane_index],
&dma_buf->strides[plane_index],
&dma_buf->offsets[plane_index],
&dma_buf->drm_modifier,
error);
if (egl_image == EGL_NO_IMAGE_KHR)
return FALSE;
flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
cogl_texture = cogl_egl_texture_2d_new_from_image (cogl_context,
dma_buf->width,
dma_buf->height,
subformats[i],
egl_image,
flags,
error);
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
if (!cogl_texture)
return FALSE;
g_ptr_array_add (planes, cogl_texture);
}
textures = (CoglTexture**) g_ptr_array_free (g_steal_pointer (&planes),
FALSE);
buffer->dma_buf.texture = meta_multi_texture_new (multi_format,
textures,
n_planes);
}
buffer->is_y_inverted = dma_buf->is_y_inverted;
return TRUE;