swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

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:
Mlibswc/shm.c | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mlibswc/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; }