--- /dev/null
+#include <stdlib.h>
+#include <drm_fourcc.h>
+
+#include "libds/log.h"
+#include "libds/util/defs.h"
+#include "libds/interfaces/buffer.h"
+
+#include "pixel_format.h"
+#include "single-pixel-buffer-v1-server-protocol.h"
+
+#define SINGLE_PIXEL_BUFFER_MANAGER_V1_VERSION 1
+
+struct ds_single_pixel_buffer_manager_v1
+{
+ struct wl_global *global;
+
+ struct wl_listener display_destroy;
+};
+
+struct ds_single_pixel_buffer_v1 {
+ struct ds_buffer base;
+ struct wl_resource *resource;
+ uint32_t r, g, b, a;
+ uint32_t argb8888;
+};
+
+static const struct wl_buffer_interface single_pixel_buffer_wl_impl;
+
+static bool
+single_pixel_buffer_is_instance(struct wl_resource *resource)
+{
+ return wl_resource_instance_of(resource, &wl_buffer_interface,
+ &single_pixel_buffer_wl_impl);
+}
+
+static struct ds_single_pixel_buffer_v1 *
+single_pixel_buffer_v1_from_resource(struct wl_resource *resource)
+{
+ DS_ASSERT(single_pixel_buffer_is_instance(resource));
+ return wl_resource_get_user_data(resource);
+}
+
+static struct ds_buffer *
+single_pixel_buffer_from_resource(struct wl_resource *resource)
+{
+ struct ds_single_pixel_buffer_v1 *buffer;
+
+ buffer = single_pixel_buffer_v1_from_resource(resource);
+ return &buffer->base;
+}
+
+static const struct ds_buffer_resource_interface
+single_pixel_buffer_resource_iface = {
+ .name = "ds_single_pixel_buffer_v1",
+ .is_instance = single_pixel_buffer_is_instance,
+ .from_resource = single_pixel_buffer_from_resource,
+};
+
+static void
+destroy_resource(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_buffer_interface single_pixel_buffer_wl_impl = {
+ .destroy = destroy_resource,
+};
+
+static void
+single_pixel_buffer_handle_resource_destroy(struct wl_resource *resource)
+{
+ struct ds_single_pixel_buffer_v1 *buffer;
+
+ buffer = wl_resource_get_user_data(resource);
+ ds_buffer_drop(&buffer->base);
+}
+
+static void
+single_pixel_buffer_iface_destroy(struct ds_buffer *ds_buffer)
+{
+ struct ds_single_pixel_buffer_v1 *buffer;
+
+ buffer = wl_container_of(ds_buffer, buffer, base);
+ free(buffer);
+}
+
+static bool
+single_pixel_buffer_iface_begin_data_ptr_access(struct ds_buffer *ds_buffer,
+ uint32_t flags, void **data, uint32_t *format, size_t *stride)
+{
+ struct ds_single_pixel_buffer_v1 *buffer;
+
+ if (flags & ~DS_BUFFER_DATA_PTR_ACCESS_READ)
+ return false;
+
+ buffer = wl_container_of(ds_buffer, buffer, base);
+ *data = &buffer->argb8888;
+ *format = DRM_FORMAT_ARGB8888;
+ *stride = sizeof(buffer->argb8888);
+
+ return true;
+}
+
+static void
+single_pixel_buffer_iface_end_data_ptr_access(struct ds_buffer *ds_buffer)
+{
+ // This space is intentionally left blank
+}
+
+static struct wl_resource *
+single_pixel_buffer_iface_get_resource(struct ds_buffer *ds_buffer)
+{
+ struct ds_single_pixel_buffer_v1 *buffer;
+
+ buffer = wl_container_of(ds_buffer, buffer, base);
+ return buffer->resource;
+}
+
+static const struct ds_buffer_interface single_pixel_buffer_iface = {
+ .destroy = single_pixel_buffer_iface_destroy,
+ .begin_data_ptr_access = single_pixel_buffer_iface_begin_data_ptr_access,
+ .end_data_ptr_access = single_pixel_buffer_iface_end_data_ptr_access,
+ .get_resource = single_pixel_buffer_iface_get_resource,
+};
+
+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 ds_single_pixel_buffer_v1 *buffer;
+
+ buffer = calloc(1, sizeof *buffer);
+ if (!buffer) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ buffer->resource = wl_resource_create(client, &wl_buffer_interface, 1, id);
+ if (!buffer->resource) {
+ wl_client_post_no_memory(client);
+ free(buffer);
+ return;
+ }
+ wl_resource_set_implementation(buffer->resource,
+ &single_pixel_buffer_wl_impl, buffer, single_pixel_buffer_handle_resource_destroy);
+
+ ds_buffer_init(&buffer->base, &single_pixel_buffer_iface, 1, 1);
+
+ buffer->r = r;
+ buffer->g = g;
+ buffer->b = b;
+ buffer->a = a;
+
+ buffer->argb8888 = (((uint32_t)((a / (double)0xffffffff) * 255)) << 24) |
+ (((uint32_t)((r / (double)0xffffffff) * 255)) << 16) |
+ (((uint32_t)((g / (double)0xffffffff) * 255)) << 8) |
+ ((uint32_t)((b / (double)0xffffffff) * 255));
+}
+
+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;
+
+ resource = wl_resource_create(client,
+ &wp_single_pixel_buffer_manager_v1_interface, version, id);
+ if (!resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &manager_impl, NULL, NULL);
+}
+
+static void
+manager_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_single_pixel_buffer_manager_v1 *manager;
+
+ manager = wl_container_of(listener, manager, display_destroy);
+ wl_global_destroy(manager->global);
+ free(manager);
+}
+
+WL_EXPORT struct ds_single_pixel_buffer_manager_v1 *
+ds_single_pixel_buffer_manager_v1_create(struct wl_display *display)
+{
+ struct ds_single_pixel_buffer_manager_v1 *manager;
+
+ DS_RETURN_VAL_IF_FAIL(display, NULL);
+
+ 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_BUFFER_MANAGER_V1_VERSION,
+ NULL, manager_bind);
+ if (!manager->global) {
+ free(manager);
+ return NULL;
+ }
+
+ manager->display_destroy.notify = manager_handle_display_destroy;
+ wl_display_add_destroy_listener(display, &manager->display_destroy);
+
+ ds_buffer_register_resource_interface(&single_pixel_buffer_resource_iface);
+
+ return manager;
+}
+
+WL_EXPORT struct ds_single_pixel_buffer_v1 *
+ds_single_pixel_buffer_v1_from_buffer(struct ds_buffer *ds_buffer)
+{
+ struct ds_single_pixel_buffer_v1 *buffer;
+
+ DS_RETURN_VAL_IF_FAIL(ds_buffer, NULL);
+
+ if (ds_buffer->iface != &single_pixel_buffer_iface)
+ return NULL;
+
+ return wl_container_of(ds_buffer, buffer, base);
+}
+