From 2cb7499735b4d1955997e7125fe48aa60bc1bb45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 19 Jan 2022 11:49:32 +0100 Subject: [PATCH] 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: --- src/meson.build | 3 + src/wayland/meta-wayland-buffer.c | 18 ++ src/wayland/meta-wayland-buffer.h | 7 + .../meta-wayland-single-pixel-buffer.c | 180 ++++++++++++++++++ .../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(-) create mode 100644 src/wayland/meta-wayland-single-pixel-buffer.c create mode 100644 src/wayland/meta-wayland-single-pixel-buffer.h diff --git a/src/meson.build b/src/meson.build index fbe9fb835..49a28137b 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 ec01546c7..557952b6f 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 c47d2227e..0f83b67de 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 000000000..54bfdac4d --- /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 000000000..4b0deb9e6 --- /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 + +#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 2279e894b..c20bbbe29 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 ee7602814..3864e0706 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 ec7a55aaa..9d066b19c 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);