summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels De Graef <niels.degraef@barco.com>2020-04-09 15:30:07 +0200
committerNiels De Graef <niels.degraef@barco.com>2020-04-09 15:30:07 +0200
commit302128d6bb91c93d24dff60467a0416a0a301932 (patch)
tree4e9b1e12c5421c6c9c9ff7d4988102acac1feeb0
parentee17ddc18e1329f6ac2b46dc97375c3ecb1d4667 (diff)
downloadmutter-wip/nielsdg/meta-multi-texture.tar.gz
-rw-r--r--src/wayland/meta-wayland-buffer.c217
-rw-r--r--src/wayland/meta-wayland.c20
2 files changed, 179 insertions, 58 deletions
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index 1f8812ca6..a0430b12c 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -210,6 +210,9 @@ shm_buffer_get_format (struct wl_shm_buffer *shm_buffer,
components = COGL_TEXTURE_COMPONENTS_RGB;
break;
#endif
+ case WL_SHM_FORMAT_NV12:
+ multi_format = META_MULTI_TEXTURE_FORMAT_NV12;
+ break;
default:
g_warn_if_reached ();
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
@@ -234,19 +237,37 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
struct wl_shm_buffer *shm_buffer;
int stride, width, height;
MetaMultiTextureFormat multi_format;
- CoglPixelFormat cogl_format;
CoglTextureComponents components;
- CoglBitmap *bitmap;
- CoglTexture *new_cogl_tex;
+ uint8_t h_factors[3], v_factors[3], bpp[3];
+ CoglPixelFormat subformats[3];
+ guint i, n_planes;
+ gsize plane_offset = 0;
+ guint8 *data;
+ GPtrArray *planes;
shm_buffer = wl_shm_buffer_get (buffer->resource);
+
+ /* Query the necessary properties */
stride = wl_shm_buffer_get_stride (shm_buffer);
width = wl_shm_buffer_get_width (shm_buffer);
height = wl_shm_buffer_get_height (shm_buffer);
- shm_buffer_get_format (shm_buffer, &multi_format, &cogl_format, &components);
+ shm_buffer_get_format (shm_buffer, &multi_format, &subformats[0], &components);
- /* We only support "simple" textures for now */
- g_return_val_if_fail (multi_format == META_MULTI_TEXTURE_FORMAT_SIMPLE, FALSE);
+ /* Fetch some properties from the pixel format */
+ n_planes = meta_multi_texture_format_get_n_planes (multi_format);
+ if (multi_format == META_MULTI_TEXTURE_FORMAT_SIMPLE)
+ {
+ /* In the simple case, we can fall back to CoglPixelFormat */
+ bpp[0] = cogl_pixel_format_get_bytes_per_pixel (subformats[0], 0);
+ h_factors[0] = 1; /* No subsampling */
+ v_factors[0] = 1;
+ }
+ else
+ {
+ meta_multi_texture_format_get_subformats (multi_format, subformats);
+ meta_multi_texture_format_get_bytes_per_pixel (multi_format, bpp);
+ meta_multi_texture_format_get_subsampling_factors (multi_format, h_factors, v_factors);
+ }
if (*texture &&
meta_multi_texture_get_width (*texture) == width &&
@@ -255,7 +276,7 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
{
CoglTexture *cogl_texture = meta_multi_texture_get_plane (*texture, 0);
if (cogl_texture_get_components (cogl_texture) == components &&
- _cogl_texture_get_format (cogl_texture) == cogl_format)
+ _cogl_texture_get_format (cogl_texture) == subformats[0])
{
buffer->is_y_inverted = TRUE;
return TRUE;
@@ -265,47 +286,84 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
g_clear_object (texture);
wl_shm_buffer_begin_access (shm_buffer);
+ data = wl_shm_buffer_get_data (shm_buffer);
- bitmap = cogl_bitmap_new_for_data (cogl_context,
- width, height,
- cogl_format,
- stride,
- wl_shm_buffer_get_data (shm_buffer));
-
- new_cogl_tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
- cogl_texture_set_components (new_cogl_tex, components);
-
- if (!cogl_texture_allocate (new_cogl_tex, error))
+ planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
+ for (i = 0; i < n_planes; i++)
{
- g_clear_pointer (&new_cogl_tex, cogl_object_unref);
- if (g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
+ int plane_stride;
+ CoglBitmap *plane_bitmap;
+ CoglTexture *plane_texture;
+
+ /* Adjust the stride: map to the amount of pixels and calculate how many
+ * bytes that takes in the current plane */
+ plane_stride = (stride / bpp[0]) * bpp[i] / h_factors[i];
+
+ /* Define the bitmap that of this plane */
+ plane_bitmap = cogl_bitmap_new_for_data (cogl_context,
+ width / h_factors[i],
+ height / v_factors[i],
+ subformats[i],
+ plane_stride,
+ data + plane_offset);
+ if (!plane_bitmap)
+ goto failure;
+
+ /* Create a texture out of it so we can upload it to the GPU */
+ plane_texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (plane_bitmap));
+
+ /* Separately set the components (necessary for e.g. XRGB, NV12) */
+ /* cogl_texture_set_components (plane_texture, components[i]); */
+
+ if (!cogl_texture_allocate (plane_texture, error))
{
CoglTexture2DSliced *texture_sliced;
+ cogl_clear_object (&plane_texture);
+
+ /* If it didn't work due to an NPOT size, try again with an atlas texture */
+ if (!g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
+ {
+ cogl_object_unref (plane_bitmap);
+ goto failure;
+ }
+
g_clear_error (error);
texture_sliced =
- cogl_texture_2d_sliced_new_from_bitmap (bitmap,
+ cogl_texture_2d_sliced_new_from_bitmap (plane_bitmap,
COGL_TEXTURE_MAX_WASTE);
- new_cogl_tex = COGL_TEXTURE (texture_sliced);
- cogl_texture_set_components (new_cogl_tex, components);
+ plane_texture = COGL_TEXTURE (texture_sliced);
+
+ /* cogl_texture_set_components (plane_texture, components[i]); */
- if (!cogl_texture_allocate (new_cogl_tex, error))
- g_clear_pointer (&new_cogl_tex, cogl_object_unref);
+ if (!cogl_texture_allocate (plane_texture, error))
+ {
+ cogl_clear_object (&plane_texture);
+ goto failure;
+ }
}
+
+ g_ptr_array_add (planes, plane_texture);
+
+ /* Calculate the next plane start in the buffer (consider subsampling) */
+ plane_offset += plane_stride * (height / v_factors[i]);
}
- cogl_object_unref (bitmap);
+ *texture = meta_multi_texture_new (multi_format,
+ (CoglTexture **) g_ptr_array_free (planes, FALSE),
+ n_planes);
wl_shm_buffer_end_access (shm_buffer);
- if (!new_cogl_tex)
- return FALSE;
-
- *texture = meta_multi_texture_new_simple (new_cogl_tex);
buffer->is_y_inverted = TRUE;
-
return TRUE;
+
+failure:
+ wl_shm_buffer_end_access (shm_buffer);
+ g_ptr_array_free (planes, TRUE);
+ *texture = NULL;
+ return FALSE;
}
static gboolean
@@ -550,48 +608,91 @@ process_shm_buffer_damage (MetaWaylandBuffer *buffer,
GError **error)
{
struct wl_shm_buffer *shm_buffer;
- int i, n_rectangles;
gboolean set_texture_failed = FALSE;
- MetaMultiTextureFormat multi_format;
- CoglPixelFormat cogl_format;
- CoglTexture *cogl_texture;
+ MetaMultiTextureFormat multi_format = META_MULTI_TEXTURE_FORMAT_SIMPLE;
+ CoglTextureComponents components;
+ const uint8_t *data;
+ int32_t stride, height;
+ uint8_t h_factors[3], v_factors[3], bpp[3];
+ CoglPixelFormat subformats[3];
+ gsize plane_offset = 0;
+ guint i, n_planes;
+ int j, n_rectangles;
n_rectangles = cairo_region_num_rectangles (region);
shm_buffer = wl_shm_buffer_get (buffer->resource);
- shm_buffer_get_format (shm_buffer, &multi_format, &cogl_format, NULL);
- g_return_val_if_fail (multi_format == META_MULTI_TEXTURE_FORMAT_SIMPLE, FALSE);
- cogl_texture = meta_multi_texture_get_plane (texture, 0);
-
+ /* Get the data */
wl_shm_buffer_begin_access (shm_buffer);
+ data = wl_shm_buffer_get_data (shm_buffer);
+
+ /* Query the necessary properties */
+ stride = wl_shm_buffer_get_stride (shm_buffer);
+ height = wl_shm_buffer_get_height (shm_buffer);
+ shm_buffer_get_format (shm_buffer, &multi_format, &subformats[0], &components);
- for (i = 0; i < n_rectangles; i++)
+ /* Fetch some properties from the pixel format */
+ n_planes = meta_multi_texture_format_get_n_planes (multi_format);
+ if (multi_format == META_MULTI_TEXTURE_FORMAT_SIMPLE)
{
- const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
- int32_t stride = wl_shm_buffer_get_stride (shm_buffer);
- cairo_rectangle_int_t rect;
- int bpp;
-
- bpp = cogl_pixel_format_get_bytes_per_pixel (cogl_format, 0);
- cairo_region_get_rectangle (region, i, &rect);
-
- if (!_cogl_texture_set_region (cogl_texture,
- rect.width, rect.height,
- cogl_format,
- stride,
- data + rect.x * bpp + rect.y * stride,
- rect.x, rect.y,
- 0,
- error))
+ /* In the simple case, we can fall back to CoglPixelFormat */
+ bpp[0] = cogl_pixel_format_get_bytes_per_pixel (subformats[0], 0);
+ h_factors[0] = 1; /* No subsampling */
+ v_factors[0] = 1;
+ }
+ else
+ {
+ meta_multi_texture_format_get_subformats (multi_format, subformats);
+ meta_multi_texture_format_get_bytes_per_pixel (multi_format, bpp);
+ meta_multi_texture_format_get_subsampling_factors (multi_format, h_factors, v_factors);
+ }
+
+ /* Go over each plane and process the regions */
+ for (i = 0; i < n_planes; i++)
+ {
+ CoglTexture *plane;
+ int plane_stride;
+
+ plane = meta_multi_texture_get_plane (texture, i);
+ plane_stride = (stride / bpp[0]) * bpp[i] / h_factors[i];
+
+ for (j = 0; j < n_rectangles; j++)
{
- set_texture_failed = TRUE;
- break;
+ cairo_rectangle_int_t rect;
+ gsize rect_offset;
+
+ cairo_region_get_rectangle (region, j, &rect);
+
+ /* It's possible we get a faulty rectangle of size zero: ignore */
+ if (rect.height == 0 || rect.width == 0)
+ continue;
+
+ rect_offset = plane_offset
+ + rect.y * plane_stride / v_factors[i] /* Find the right row */
+ + rect.x * bpp[i] / h_factors[i]; /* and the right column */
+
+ if (!_cogl_texture_set_region (plane,
+ rect.width / h_factors[i],
+ rect.height / v_factors[i],
+ subformats[i],
+ plane_stride,
+ data + rect_offset,
+ rect.x, rect.y,
+ 0,
+ error))
+ {
+ set_texture_failed = TRUE;
+ goto out;
+ }
}
+
+ /* Calculate the next plane start in the buffer (consider subsampling) */
+ plane_offset += plane_stride * (height / v_factors[i]);
}
+out:
wl_shm_buffer_end_access (shm_buffer);
-
return !set_texture_failed;
}
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index b2eab006b..f2a40137d 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -307,6 +307,24 @@ meta_wayland_log_func (const char *fmt,
}
static void
+add_supported_shm_formats (struct wl_display *display)
+{
+ guint i;
+
+ /* Note that a Wayland compositor should support WL_SHM_FORMAT_ARGB8888 and
+ * WL_SHM_FORMAT_XRGB8888 by default, so no need to add it here. */
+ static const guint32 SUPPORTED_FORMATS[] = {
+ WL_SHM_FORMAT_NV12,
+ WL_SHM_FORMAT_NV21,
+ };
+
+ for (i = 0; i < G_N_ELEMENTS (SUPPORTED_FORMATS); i++)
+ {
+ wl_display_add_shm_format (display, SUPPORTED_FORMATS[i]);
+ }
+}
+
+static void
meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
{
wl_list_init (&compositor->frame_callbacks);
@@ -318,6 +336,8 @@ meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
compositor->wayland_display = wl_display_create ();
if (compositor->wayland_display == NULL)
g_error ("Failed to create the global wl_display");
+
+ add_supported_shm_formats (compositor->wayland_display);
}
static void