commit 3333dfd86da6a407fd39ad77d2f5cb85cd8ba824
parent cae8594c740dd5f6d06b35bfda587a68c063b203
Author: Michael Forney <mforney@mforney.org>
Date: Fri, 7 Feb 2014 04:07:06 -0800
shm: Use our own wl_shm implementation
Diffstat:
M | libswc/shm.c | | | 216 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
M | libswc/wayland_buffer.c | | | 74 | -------------------------------------------------------------------------- |
2 files changed, 213 insertions(+), 77 deletions(-)
diff --git a/libswc/shm.c b/libswc/shm.c
@@ -1,6 +1,10 @@
/* swc: libswc/shm.c
*
- * Copyright (c) 2013 Michael Forney
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Based in part upon wayland-shm.c from wayland, which is:
+ *
+ * Copyright © 2008 Kristian Høgsberg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,13 +27,210 @@
#include "shm.h"
#include "internal.h"
+#include "util.h"
+#include "wayland_buffer.h"
-#include <stddef.h>
-#include <wld/wld.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <wayland-server.h>
#include <wld/pixman.h>
+#include <wld/wld.h>
struct swc_shm swc_shm;
+static struct
+{
+ struct wl_global * global;
+} shm;
+
+struct pool
+{
+ struct wl_resource * resource;
+ void * data;
+ uint32_t size;
+ unsigned references;
+};
+
+struct pool_reference
+{
+ struct wld_destructor destructor;
+ struct pool * pool;
+};
+
+static void unref_pool(struct wl_resource * resource)
+{
+ struct pool * pool = wl_resource_get_user_data(resource);
+
+ if (--pool->references > 0)
+ return;
+
+ munmap(pool->data, pool->size);
+ free(pool);
+}
+
+static void handle_buffer_destroy(struct wld_destructor * destructor)
+{
+ struct pool_reference * reference
+ = CONTAINER_OF(destructor, typeof(*reference), destructor);
+
+ unref_pool(reference->pool->resource);
+}
+
+static inline uint32_t format_shm_to_wld(uint32_t format)
+{
+ switch (format)
+ {
+ case WL_SHM_FORMAT_ARGB8888:
+ return WLD_FORMAT_ARGB8888;
+ case WL_SHM_FORMAT_XRGB8888:
+ return WLD_FORMAT_XRGB8888;
+ default:
+ return format;
+ }
+}
+
+static void create_buffer(struct wl_client * client,
+ struct wl_resource * resource, uint32_t id,
+ int32_t offset, int32_t width, int32_t height,
+ int32_t stride, uint32_t format)
+{
+ struct pool * pool = wl_resource_get_user_data(resource);
+ struct pool_reference * reference;
+ struct wld_buffer * buffer;
+ struct wl_resource * buffer_resource;
+ union wld_object object;
+
+ if (offset > pool->size || offset < 0)
+ {
+ wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_STRIDE,
+ "offset is too big or negative");
+ return;
+ }
+
+ object.ptr = (void *)((uintptr_t) pool->data + offset);
+ buffer = wld_import_buffer(swc.shm->context, WLD_OBJECT_DATA, object,
+ width, height, format_shm_to_wld(format),
+ stride);
+
+ if (!buffer)
+ goto error0;
+
+ buffer_resource = swc_wayland_buffer_create_resource(client, id, buffer);
+
+ if (!buffer_resource)
+ goto error1;
+
+ if (!(reference = malloc(sizeof *reference)))
+ goto error2;
+
+ reference->pool = pool;
+ reference->destructor.destroy = &handle_buffer_destroy;
+ wld_buffer_add_destructor(buffer, &reference->destructor);
+ ++pool->references;
+
+ return;
+
+ error2:
+ wl_resource_destroy(buffer_resource);
+ error1:
+ wld_buffer_unreference(buffer);
+ error0:
+ wl_resource_post_no_memory(resource);
+}
+
+static void destroy(struct wl_client * client, struct wl_resource * resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void resize(struct wl_client * client, struct wl_resource * resource,
+ int32_t size)
+{
+ struct pool * pool = wl_resource_get_user_data(resource);
+ void * data;
+
+ data = mremap(pool->data, pool->size, size, MREMAP_MAYMOVE);
+
+ if (data == MAP_FAILED)
+ {
+ wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD,
+ "mremap failed: %s", strerror(errno));
+ return;
+ }
+
+ pool->data = data;
+ pool->size = size;
+}
+
+static struct wl_shm_pool_interface shm_pool_implementation = {
+ .create_buffer = &create_buffer,
+ .destroy = &destroy,
+ .resize = &resize
+};
+
+static void create_pool(struct wl_client * client,
+ struct wl_resource * resource, uint32_t id,
+ int32_t fd, int32_t size)
+{
+ struct pool * pool;
+
+ if (!(pool = malloc(sizeof *pool)))
+ {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ pool->resource = wl_resource_create(client, &wl_shm_pool_interface,
+ wl_resource_get_version(resource), id);
+
+ if (!pool->resource)
+ {
+ wl_resource_post_no_memory(resource);
+ goto error0;
+ }
+
+ wl_resource_set_implementation(pool->resource, &shm_pool_implementation,
+ pool, &unref_pool);
+ pool->data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+
+ if (pool->data == MAP_FAILED)
+ {
+ wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD,
+ "mmap failed: %s", strerror(errno));
+ goto error1;
+ }
+
+ pool->size = size;
+ pool->references = 1;
+
+ return;
+
+ error1:
+ wl_resource_destroy(pool->resource);
+ error0:
+ free(pool);
+}
+
+static struct wl_shm_interface shm_implementation = {
+ .create_pool = &create_pool
+};
+
+static void bind_shm(struct wl_client * client, void * data, uint32_t version,
+ uint32_t id)
+{
+ struct wl_resource * resource;
+
+ if (version >= 1)
+ version = 1;
+
+ resource = wl_resource_create(client, &wl_shm_interface, version, id);
+ wl_resource_set_implementation(resource, &shm_implementation, NULL, NULL);
+
+ wl_shm_send_format(resource, WL_SHM_FORMAT_XRGB8888);
+ wl_shm_send_format(resource, WL_SHM_FORMAT_ARGB8888);
+}
+
bool swc_shm_initialize()
{
if (!(swc.shm->context = wld_pixman_create_context()))
@@ -38,8 +239,16 @@ bool swc_shm_initialize()
if (!(swc.shm->renderer = wld_create_renderer(swc.shm->context)))
goto error1;
+ shm.global = wl_global_create(swc.display, &wl_shm_interface, 1,
+ NULL, &bind_shm);
+
+ if (!shm.global)
+ goto error2;
+
return true;
+ error2:
+ wld_destroy_renderer(swc.shm->renderer);
error1:
wld_destroy_context(swc.shm->context);
error0:
@@ -48,6 +257,7 @@ bool swc_shm_initialize()
void swc_shm_finalize()
{
+ wl_global_destroy(shm.global);
wld_destroy_renderer(swc.shm->renderer);
wld_destroy_context(swc.shm->context);
}
diff --git a/libswc/wayland_buffer.c b/libswc/wayland_buffer.c
@@ -29,12 +29,6 @@
#include <wld/wld.h>
#include <wld/pixman.h>
-struct wayland_buffer
-{
- struct wld_buffer * wld;
- struct wl_listener destroy_listener;
-};
-
static void destroy(struct wl_client * client, struct wl_resource * resource)
{
wl_resource_destroy(resource);
@@ -44,30 +38,6 @@ static const struct wl_buffer_interface buffer_implementation = {
.destroy = &destroy
};
-/* NOTE: Needed because the implementation for SHM buffers comes from
- * libwayland-server. */
-static void handle_buffer_destroy(struct wl_listener * listener, void * data)
-{
- struct wayland_buffer * buffer
- = CONTAINER_OF(listener, typeof(*buffer), destroy_listener);
-
- wld_buffer_unreference(buffer->wld);
- free(buffer);
-}
-
-static inline uint32_t format_shm_to_wld(uint32_t format)
-{
- switch (format)
- {
- case WL_SHM_FORMAT_ARGB8888:
- return WLD_FORMAT_ARGB8888;
- case WL_SHM_FORMAT_XRGB8888:
- return WLD_FORMAT_XRGB8888;
- default:
- return format;
- }
-}
-
struct wld_buffer * swc_wayland_buffer_get(struct wl_resource * resource)
{
if (wl_resource_instance_of(resource, &wl_buffer_interface,
@@ -76,50 +46,6 @@ struct wld_buffer * swc_wayland_buffer_get(struct wl_resource * resource)
return wl_resource_get_user_data(resource);
}
- struct wl_listener * listener;
- struct wayland_buffer * buffer;
-
- listener = wl_resource_get_destroy_listener(resource,
- &handle_buffer_destroy);
-
- if (listener)
- {
- buffer = CONTAINER_OF(listener, typeof(*buffer), destroy_listener);
-
- return buffer->wld;
- }
-
- if (!(buffer = malloc(sizeof *buffer)))
- goto error0;
-
- struct wl_shm_buffer * shm_buffer;
-
- if ((shm_buffer = wl_shm_buffer_get(resource)))
- {
- union wld_object object = {
- .ptr = wl_shm_buffer_get_data(shm_buffer)
- };
-
- buffer->wld = wld_import_buffer
- (swc.shm->context, WLD_OBJECT_DATA, object,
- wl_shm_buffer_get_width(shm_buffer),
- wl_shm_buffer_get_height(shm_buffer),
- format_shm_to_wld(wl_shm_buffer_get_format(shm_buffer)),
- wl_shm_buffer_get_stride(shm_buffer));
- }
-
- if (!buffer->wld)
- goto error1;
-
- buffer->destroy_listener.notify = &handle_buffer_destroy;
- wl_resource_add_destroy_listener(resource,
- &buffer->destroy_listener);
-
- return buffer->wld;
-
- error1:
- free(buffer);
- error0:
return NULL;
}