[mutter] wayland: Add single pixel buffer support



commit 2cb7499735b4d1955997e7125fe48aa60bc1bb45
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Wed Jan 19 11:49:32 2022 +0100

    wayland: Add single pixel buffer support
    
    The "single pixel buffer" Wayland protocol extension provides a way for
    clients to create 1x1 buffers with a single color, specified by
    providing the color channels (red, green and blue) as well as the
    alpha channel as a 32 bit unsigned integer.
    
    For now, this is turned into a 1x1 texture. Future potential
    improvements is to hook things up to the scanout candidate logic and
    turn it into a scanout capable DMA buffer.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2246>

 src/meson.build                                |   3 +
 src/wayland/meta-wayland-buffer.c              |  18 +++
 src/wayland/meta-wayland-buffer.h              |   7 +
 src/wayland/meta-wayland-single-pixel-buffer.c | 180 +++++++++++++++++++++++++
 src/wayland/meta-wayland-single-pixel-buffer.h |  41 ++++++
 src/wayland/meta-wayland-surface.c             |   6 +-
 src/wayland/meta-wayland-versions.h            |   1 +
 src/wayland/meta-wayland.c                     |   1 +
 8 files changed, 255 insertions(+), 2 deletions(-)
---
diff --git a/src/meson.build b/src/meson.build
index fbe9fb8354..49a28137b8 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -611,6 +611,8 @@ if have_wayland
     'wayland/meta-wayland-seat.h',
     'wayland/meta-wayland-shell-surface.c',
     'wayland/meta-wayland-shell-surface.h',
+    'wayland/meta-wayland-single-pixel-buffer.c',
+    'wayland/meta-wayland-single-pixel-buffer.h',
     'wayland/meta-wayland-subsurface.c',
     'wayland/meta-wayland-subsurface.h',
     'wayland/meta-wayland-surface.c',
@@ -928,6 +930,7 @@ if have_wayland
     ['presentation-time', 'stable', ],
     ['primary-selection', 'unstable', 'v1', ],
     ['relative-pointer', 'unstable', 'v1', ],
+    ['single-pixel-buffer', 'staging', 'v1', ],
     ['tablet', 'unstable', 'v2', ],
     ['text-input', 'unstable', 'v3', ],
     ['viewporter', 'stable', ],
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index ec01546c7b..557952b6fe 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -140,6 +140,7 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
   MetaWaylandEglStream *stream;
 #endif
   MetaWaylandDmaBufBuffer *dma_buf;
+  MetaWaylandSinglePixelBuffer *single_pixel_buffer;
 
   if (wl_shm_buffer_get (buffer->resource) != NULL)
     {
@@ -194,6 +195,14 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
       return TRUE;
     }
 
+  single_pixel_buffer = meta_wayland_single_pixel_buffer_from_buffer (buffer);
+  if (single_pixel_buffer)
+    {
+      buffer->single_pixel.single_pixel_buffer = single_pixel_buffer;
+      buffer->type = META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL;
+      return TRUE;
+    }
+
   return FALSE;
 }
 
@@ -576,6 +585,10 @@ meta_wayland_buffer_attach (MetaWaylandBuffer  *buffer,
       return meta_wayland_dma_buf_buffer_attach (buffer,
                                                  texture,
                                                  error);
+    case META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL:
+      return meta_wayland_single_pixel_buffer_attach (buffer,
+                                                      texture,
+                                                      error);
     case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
       g_assert_not_reached ();
       return FALSE;
@@ -682,6 +695,7 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
     case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
 #endif
     case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
+    case META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL:
       res = TRUE;
       break;
     case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
@@ -757,6 +771,7 @@ meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
   switch (buffer->type)
     {
     case META_WAYLAND_BUFFER_TYPE_SHM:
+    case META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL:
       return NULL;
     case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
       return try_acquire_egl_image_scanout (buffer, onscreen);
@@ -795,6 +810,9 @@ meta_wayland_buffer_finalize (GObject *object)
 #endif
   g_clear_pointer (&buffer->dma_buf.texture, cogl_object_unref);
   g_clear_object (&buffer->dma_buf.dma_buf);
+  g_clear_pointer (&buffer->single_pixel.single_pixel_buffer,
+                   meta_wayland_single_pixel_buffer_free);
+  cogl_clear_object (&buffer->single_pixel.texture);
 
   G_OBJECT_CLASS (meta_wayland_buffer_parent_class)->finalize (object);
 }
diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h
index c47d2227eb..0f83b67de1 100644
--- a/src/wayland/meta-wayland-buffer.h
+++ b/src/wayland/meta-wayland-buffer.h
@@ -32,6 +32,7 @@
 #include "wayland/meta-wayland-types.h"
 #include "wayland/meta-wayland-egl-stream.h"
 #include "wayland/meta-wayland-dma-buf.h"
+#include "wayland/meta-wayland-single-pixel-buffer.h"
 
 typedef enum _MetaWaylandBufferType
 {
@@ -42,6 +43,7 @@ typedef enum _MetaWaylandBufferType
   META_WAYLAND_BUFFER_TYPE_EGL_STREAM,
 #endif
   META_WAYLAND_BUFFER_TYPE_DMA_BUF,
+  META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL,
 } MetaWaylandBufferType;
 
 struct _MetaWaylandBuffer
@@ -71,6 +73,11 @@ struct _MetaWaylandBuffer
     MetaWaylandDmaBufBuffer *dma_buf;
     CoglTexture *texture;
   } dma_buf;
+
+  struct {
+    MetaWaylandSinglePixelBuffer *single_pixel_buffer;
+    CoglTexture *texture;
+  } single_pixel;
 };
 
 #define META_TYPE_WAYLAND_BUFFER (meta_wayland_buffer_get_type ())
diff --git a/src/wayland/meta-wayland-single-pixel-buffer.c b/src/wayland/meta-wayland-single-pixel-buffer.c
new file mode 100644
index 0000000000..54bfdac4df
--- /dev/null
+++ b/src/wayland/meta-wayland-single-pixel-buffer.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "wayland/meta-wayland-single-pixel-buffer.h"
+
+#include "backends/meta-backend-private.h"
+#include "wayland/meta-wayland-buffer.h"
+#include "wayland/meta-wayland-private.h"
+
+#include "single-pixel-buffer-v1-server-protocol.h"
+
+struct _MetaWaylandSinglePixelBuffer
+{
+  uint32_t r;
+  uint32_t g;
+  uint32_t b;
+  uint32_t a;
+};
+
+static void
+buffer_destroy (struct wl_client   *client,
+                struct wl_resource *resource)
+{
+  wl_resource_destroy (resource);
+}
+
+static const struct wl_buffer_interface single_pixel_buffer_implementation =
+{
+  buffer_destroy,
+};
+
+static void
+single_pixel_buffer_manager_destroy (struct wl_client *client,
+                                     struct wl_resource *resource)
+{
+  wl_resource_destroy (resource);
+}
+
+static void
+single_pixel_buffer_manager_create_1px_rgba32_buffer (struct wl_client   *client,
+                                                      struct wl_resource *resource,
+                                                      uint32_t            buffer_id,
+                                                      uint32_t            r,
+                                                      uint32_t            g,
+                                                      uint32_t            b,
+                                                      uint32_t            a)
+{
+  MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource);
+  MetaWaylandSinglePixelBuffer *single_pixel_buffer;
+  struct wl_resource *buffer_resource;
+
+  single_pixel_buffer = g_new0 (MetaWaylandSinglePixelBuffer, 1);
+  single_pixel_buffer->r = r;
+  single_pixel_buffer->g = g;
+  single_pixel_buffer->b = b;
+  single_pixel_buffer->a = a;
+
+  buffer_resource =
+    wl_resource_create (client, &wl_buffer_interface, 1, buffer_id);
+  wl_resource_set_implementation (buffer_resource,
+                                  &single_pixel_buffer_implementation,
+                                  single_pixel_buffer, NULL);
+  meta_wayland_buffer_from_resource (compositor, buffer_resource);
+}
+
+static const struct wp_single_pixel_buffer_manager_v1_interface
+  single_pixel_buffer_manager_implementation =
+{
+  single_pixel_buffer_manager_destroy,
+  single_pixel_buffer_manager_create_1px_rgba32_buffer,
+};
+
+static void
+single_pixel_buffer_manager_bind (struct wl_client *client,
+                                  void             *user_data,
+                                  uint32_t          version,
+                                  uint32_t          id)
+{
+  MetaWaylandCompositor *compositor = user_data;
+  struct wl_resource *resource;
+
+  resource = wl_resource_create (client,
+                                 &wp_single_pixel_buffer_manager_v1_interface,
+                                 version, id);
+  wl_resource_set_implementation (resource,
+                                  &single_pixel_buffer_manager_implementation,
+                                  compositor, NULL);
+}
+
+gboolean
+meta_wayland_single_pixel_buffer_attach (MetaWaylandBuffer  *buffer,
+                                         CoglTexture       **texture,
+                                         GError            **error)
+{
+  MetaBackend *backend = meta_get_backend ();
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  CoglContext *cogl_context =
+    clutter_backend_get_cogl_context (clutter_backend);
+  MetaWaylandSinglePixelBuffer *single_pixel_buffer =
+    wl_resource_get_user_data (buffer->resource);
+  uint8_t data[4];
+  CoglPixelFormat pixel_format;
+  CoglTexture2D *tex_2d;
+
+  if (buffer->single_pixel.texture)
+    return TRUE;
+
+  data[0] = single_pixel_buffer->b / (UINT32_MAX / 0xff);
+  data[1] = single_pixel_buffer->g / (UINT32_MAX / 0xff);
+  data[2] = single_pixel_buffer->r / (UINT32_MAX / 0xff);
+  data[3] = single_pixel_buffer->a / (UINT32_MAX / 0xff);
+
+  if (data[3] == UINT8_MAX)
+    pixel_format = COGL_PIXEL_FORMAT_BGR_888;
+  else
+    pixel_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
+
+  tex_2d = cogl_texture_2d_new_from_data (cogl_context,
+                                          1, 1,
+                                          pixel_format,
+                                          4, data,
+                                          error);
+  if (!tex_2d)
+    return FALSE;
+
+  buffer->single_pixel.texture = COGL_TEXTURE (tex_2d);
+
+  cogl_clear_object (texture);
+  *texture = cogl_object_ref (buffer->single_pixel.texture);
+  return TRUE;
+}
+
+MetaWaylandSinglePixelBuffer *
+meta_wayland_single_pixel_buffer_from_buffer (MetaWaylandBuffer *buffer)
+{
+  if (!buffer->resource)
+    return NULL;
+
+  if (wl_resource_instance_of (buffer->resource, &wl_buffer_interface,
+                               &single_pixel_buffer_implementation))
+    return wl_resource_get_user_data (buffer->resource);
+
+  return NULL;
+}
+
+void
+meta_wayland_single_pixel_buffer_free (MetaWaylandSinglePixelBuffer *single_pixel_buffer)
+{
+  g_free (single_pixel_buffer);
+}
+
+void
+meta_wayland_init_single_pixel_buffer_manager (MetaWaylandCompositor *compositor)
+{
+  if (!wl_global_create (compositor->wayland_display,
+                         &wp_single_pixel_buffer_manager_v1_interface,
+                         META_WP_SINGLE_PIXEL_BUFFER_V1_VERSION,
+                         compositor,
+                         single_pixel_buffer_manager_bind))
+    g_warning ("Failed to create wp_single_pixel_buffer_manager_v1 global");
+}
diff --git a/src/wayland/meta-wayland-single-pixel-buffer.h b/src/wayland/meta-wayland-single-pixel-buffer.h
new file mode 100644
index 0000000000..4b0deb9e63
--- /dev/null
+++ b/src/wayland/meta-wayland-single-pixel-buffer.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#ifndef META_WAYLAND_SINGLE_PIXEL_BUFFER_H
+#define META_WAYLAND_SINGLE_PIXEL_BUFFER_H
+
+#include <glib.h>
+
+#include "cogl/cogl.h"
+#include "wayland/meta-wayland-types.h"
+
+typedef struct _MetaWaylandSinglePixelBuffer MetaWaylandSinglePixelBuffer;
+
+gboolean meta_wayland_single_pixel_buffer_attach (MetaWaylandBuffer  *buffer,
+                                                  CoglTexture       **texture,
+                                                  GError            **error);
+
+MetaWaylandSinglePixelBuffer * meta_wayland_single_pixel_buffer_from_buffer (MetaWaylandBuffer *buffer);
+
+void meta_wayland_init_single_pixel_buffer_manager (MetaWaylandCompositor *compositor);
+
+void meta_wayland_single_pixel_buffer_free (MetaWaylandSinglePixelBuffer *single_pixel_buffer);
+
+#endif /* META_WAYLAND_SINGLE_PIXEL_BUFFER_H */
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 2279e894b6..c20bbbe291 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -780,8 +780,10 @@ meta_wayland_surface_apply_state (MetaWaylandSurface      *surface,
        * it until is replaced by a subsequent wl_surface.commit or when the
        * wl_surface is destroyed.
        */
-      surface->buffer_held = (state->buffer &&
-                              !wl_shm_buffer_get (state->buffer->resource));
+      surface->buffer_held =
+        (state->buffer &&
+         (state->buffer->type != META_WAYLAND_BUFFER_TYPE_SHM &&
+          state->buffer->type != META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL));
     }
 
   if (state->scale > 0)
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index ee7602814a..3864e07063 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -54,5 +54,6 @@
 #define META_ZWP_PRIMARY_SELECTION_V1_VERSION 1
 #define META_WP_PRESENTATION_VERSION        1
 #define META_XDG_ACTIVATION_V1_VERSION 1
+#define META_WP_SINGLE_PIXEL_BUFFER_V1_VERSION 1
 
 #endif
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index ec7a55aaa5..9d066b19cb 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -627,6 +627,7 @@ meta_wayland_compositor_new (MetaContext *context)
   meta_wayland_pointer_constraints_init (compositor);
   meta_wayland_xdg_foreign_init (compositor);
   init_dma_buf_support (compositor);
+  meta_wayland_init_single_pixel_buffer_manager (compositor);
   meta_wayland_keyboard_shortcuts_inhibit_init (compositor);
   meta_wayland_surface_inhibit_shortcuts_dialog_init ();
   meta_wayland_text_input_init (compositor);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]