diff --git a/include/wlr/types/wlr_single_pixel_buffer_v1.h b/include/wlr/types/wlr_single_pixel_buffer_v1.h new file mode 100644 index 00000000..3eba546a --- /dev/null +++ b/include/wlr/types/wlr_single_pixel_buffer_v1.h @@ -0,0 +1,19 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_SINGLE_PIXEL_BUFFER_V1 +#define WLR_TYPES_WLR_SINGLE_PIXEL_BUFFER_V1 + +#include + +struct wlr_single_pixel_buffer_manager_v1; + +struct wlr_single_pixel_buffer_manager_v1 *wlr_single_pixel_buffer_manager_v1_create( + struct wl_display *display); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 4cc01874..920c181c 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -21,6 +21,7 @@ protocols = { 'xdg-activation-v1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', 'drm-lease-v1': wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', 'ext-session-lock-v1': wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml', + 'single-pixel-buffer-v1': wl_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', # Unstable upstream protocols 'fullscreen-shell-unstable-v1': wl_protocol_dir / 'unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml', diff --git a/types/meson.build b/types/meson.build index 53bf852b..19360eb7 100644 --- a/types/meson.build +++ b/types/meson.build @@ -63,6 +63,7 @@ wlr_files += files( 'wlr_screencopy_v1.c', 'wlr_server_decoration.c', 'wlr_session_lock_v1.c', + 'wlr_single_pixel_buffer_v1.c', 'wlr_subcompositor.c', 'wlr_switch.c', 'wlr_tablet_pad.c', diff --git a/types/wlr_single_pixel_buffer_v1.c b/types/wlr_single_pixel_buffer_v1.c new file mode 100644 index 00000000..e4dac829 --- /dev/null +++ b/types/wlr_single_pixel_buffer_v1.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include "single-pixel-buffer-v1-protocol.h" + +#define SINGLE_PIXEL_MANAGER_VERSION 1 + +struct wlr_single_pixel_buffer_manager_v1 { + struct wl_global *global; + + struct wl_listener display_destroy; +}; + +struct wlr_single_pixel_buffer_v1 { + struct wlr_buffer base; + struct wl_resource *resource; + uint32_t r, g, b, a; + uint8_t argb8888[4]; // packed little-endian DRM_FORMAT_ARGB8888 +}; + +static void destroy_resource(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct wl_buffer_interface wl_buffer_impl = { + .destroy = destroy_resource, +}; + +static const struct wlr_buffer_impl buffer_impl; + +static bool buffer_resource_is_instance(struct wl_resource *resource) { + return wl_resource_instance_of(resource, &wl_buffer_interface, + &wl_buffer_impl); +} + +static struct wlr_single_pixel_buffer_v1 *single_pixel_buffer_v1_from_resource( + struct wl_resource *resource) { + assert(buffer_resource_is_instance(resource)); + return wl_resource_get_user_data(resource); +} + +static struct wlr_buffer *buffer_from_resource( + struct wl_resource *resource) { + return &single_pixel_buffer_v1_from_resource(resource)->base; +} + +static const struct wlr_buffer_resource_interface buffer_resource_interface = { + .name = "single_pixel_buffer_v1", + .is_instance = buffer_resource_is_instance, + .from_resource = buffer_from_resource, +}; + +static void buffer_destroy(struct wlr_buffer *wlr_buffer) { + struct wlr_single_pixel_buffer_v1 *buffer = + wl_container_of(wlr_buffer, buffer, base); + if (buffer->resource != NULL) { + wl_resource_set_user_data(buffer->resource, NULL); + } + free(buffer); +} + +static bool buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer, + uint32_t flags, void **data, uint32_t *format, size_t *stride) { + struct wlr_single_pixel_buffer_v1 *buffer = + wl_container_of(wlr_buffer, buffer, base); + if (flags & ~WLR_BUFFER_DATA_PTR_ACCESS_READ) { + return false; // the buffer is read-only + } + *data = &buffer->argb8888; + *format = DRM_FORMAT_ARGB8888; + *stride = sizeof(buffer->argb8888); + return true; +} + +static void buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) { + // This space is intentionally left blank +} + +static const struct wlr_buffer_impl buffer_impl = { + .destroy = buffer_destroy, + .begin_data_ptr_access = buffer_begin_data_ptr_access, + .end_data_ptr_access = buffer_end_data_ptr_access, +}; + +static void buffer_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_single_pixel_buffer_v1 *buffer = single_pixel_buffer_v1_from_resource(resource); + buffer->resource = NULL; + wlr_buffer_drop(&buffer->base); +} + +static void manager_handle_create_u32_rgba_buffer(struct wl_client *client, + struct wl_resource *resource, uint32_t id, uint32_t r, uint32_t g, + uint32_t b, uint32_t a) { + struct wlr_single_pixel_buffer_v1 *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + wl_client_post_no_memory(client); + return; + } + + buffer->resource = wl_resource_create(client, &wl_buffer_interface, 1, id); + if (buffer->resource == NULL) { + wl_client_post_no_memory(client); + free(buffer); + return; + } + + wlr_buffer_init(&buffer->base, &buffer_impl, 1, 1); + wl_resource_set_implementation(buffer->resource, + &wl_buffer_impl, buffer, buffer_handle_resource_destroy); + + buffer->r = r; + buffer->g = g; + buffer->b = b; + buffer->a = a; + + double f = (double)0xFF / 0xFFFFFFFF; + buffer->argb8888[0] = (uint8_t)((double)buffer->b * f); + buffer->argb8888[1] = (uint8_t)((double)buffer->g * f); + buffer->argb8888[2] = (uint8_t)((double)buffer->r * f); + buffer->argb8888[3] = (uint8_t)((double)buffer->a * f); +} + +static const struct wp_single_pixel_buffer_manager_v1_interface manager_impl = { + .destroy = destroy_resource, + .create_u32_rgba_buffer = manager_handle_create_u32_rgba_buffer, +}; + +static void manager_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wl_resource *resource = wl_resource_create(client, + &wp_single_pixel_buffer_manager_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &manager_impl, NULL, NULL); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_single_pixel_buffer_manager_v1 *manager = + wl_container_of(listener, manager, display_destroy); + wl_global_destroy(manager->global); + free(manager); +} + +struct wlr_single_pixel_buffer_manager_v1 *wlr_single_pixel_buffer_manager_v1_create( + struct wl_display *display) { + struct wlr_single_pixel_buffer_manager_v1 *manager = calloc(1, sizeof(*manager)); + if (manager == NULL) { + return NULL; + } + + manager->global = wl_global_create(display, + &wp_single_pixel_buffer_manager_v1_interface, + SINGLE_PIXEL_MANAGER_VERSION, + NULL, manager_bind); + if (manager->global == NULL) { + free(manager); + return NULL; + } + + manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + wlr_buffer_register_resource_interface(&buffer_resource_interface); + + return manager; +}