</request>
</interface>
+ <interface name="wl_shm_pool" version="1">
+ <description summary="a shared memory pool">
+ The wl_shm_pool object encapsulates a piece of memory shared
+ between the compsitor and client. Through the wl_shm_pool
+ object, the client can allocate shared memory wl_buffer objects.
+ The objects will share the same underlying mapped memory.
+ Reusing the mapped memory avoids the setup/teardown overhead and
+ is useful when interactively resizing a surface or for many
+ small buffers.
+ </description>
+
+ <request name="create_buffer">
+ <description summary="create wl_buffer from pool">
+ Create a wl_buffer from the pool. The buffer is created a
+ offset bytes into the pool and has width and height as
+ specified. The stride arguments specifies the number of bytes
+ from beginning of one row to the beginning of the next. The
+ format is the pixel format of the buffer and must be one of
+ those advertised through the wl_shm.format event.
+
+ A buffer will keep a reference to the pool it was created from
+ so it is valid to destroy the pool immediatedly after creating
+ a buffer from it.
+ </description>
+
+ <arg name="id" type="new_id" interface="wl_buffer"/>
+ <arg name="offset" type="int"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ <arg name="stride" type="int"/>
+ <arg name="format" type="uint"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the pool">
+ Destroy the pool.
+ </description>
+ </request>
+ </interface>
+
<interface name="wl_shm" version="1">
<description summary="shared memory support">
Support for shared memory buffers.
<entry name="xrgb8888" value="1"/>
</enum>
- <request name="create_buffer">
- <description summary="create a wl_buffer">
- Transfer a shm buffer to the server. The allocated buffer
- would include at least stride * height bytes starting at the
- beginning of fd. The file descriptor is transferred over the
- socket using AF_UNIX magical features. width, height, stride
- and format describe the respective properties of the pixel
- data contained in the buffer.
+ <request name="create_pool">
+ <description summary="create a shm pool">
+ This creates wl_shm_pool object, which can be used to create
+ shared memory based wl_buffer objects. The server will mmap
+ size bytes of the passed fd, to use as backing memory for then
+ pool.
</description>
- <arg name="id" type="new_id" interface="wl_buffer"/>
+ <arg name="id" type="new_id" interface="wl_shm_pool"/>
<arg name="fd" type="fd"/>
- <arg name="width" type="int"/>
- <arg name="height" type="int"/>
- <arg name="stride" type="int"/>
- <arg name="format" type="uint"/>
+ <arg name="size" type="int"/>
</request>
<event name="format">
#include "wayland-server.h"
+struct wl_shm_pool {
+ struct wl_resource resource;
+ int refcount;
+ char *data;
+ int size;
+};
+
struct wl_shm_buffer {
struct wl_buffer buffer;
int32_t stride;
uint32_t format;
void *data;
+ struct wl_shm_pool *pool;
};
static void
+shm_pool_unref(struct wl_shm_pool *pool)
+{
+ pool->refcount--;
+ if (pool->refcount)
+ return;
+
+ munmap(pool->data, pool->size);
+ free(pool);
+}
+
+static void
destroy_buffer(struct wl_resource *resource)
{
struct wl_shm_buffer *buffer =
container_of(resource, struct wl_shm_buffer, buffer.resource);
- munmap(buffer->data, buffer->stride * buffer->buffer.height);
-
+ if (buffer->pool)
+ shm_pool_unref(buffer->pool);
free(buffer);
}
shm_buffer_destroy
};
-static struct wl_shm_buffer *
-wl_shm_buffer_init(struct wl_client *client, uint32_t id,
- int32_t width, int32_t height,
- int32_t stride, uint32_t format, void *data)
+static void
+shm_pool_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 wl_shm_pool *pool = resource->data;
struct wl_shm_buffer *buffer;
- buffer = calloc(1, sizeof *buffer);
- if (buffer == NULL)
- return NULL;
+ switch (format) {
+ case WL_SHM_FORMAT_ARGB8888:
+ case WL_SHM_FORMAT_XRGB8888:
+ break;
+ default:
+ wl_resource_post_error(resource,
+ WL_SHM_ERROR_INVALID_FORMAT,
+ "invalid format");
+ return;
+ }
+
+ if (offset < 0 || width <= 0 || height <= 0 || stride < width ||
+ INT32_MAX / stride <= height ||
+ offset > pool->size - stride * height) {
+ wl_resource_post_error(resource,
+ WL_SHM_ERROR_INVALID_STRIDE,
+ "invalid width, height or stride (%dx%d, %u)",
+ width, height, stride);
+ return;
+ }
+
+ buffer = malloc(sizeof *buffer);
+ if (buffer == NULL) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
buffer->buffer.width = width;
buffer->buffer.height = height;
buffer->format = format;
buffer->stride = stride;
- buffer->data = data;
+ buffer->data = pool->data + offset;
+ buffer->pool = pool;
+ pool->refcount++;
buffer->buffer.resource.object.id = id;
buffer->buffer.resource.object.interface = &wl_buffer_interface;
&shm_buffer_interface;
buffer->buffer.resource.data = buffer;
- buffer->buffer.resource.client = client;
+ buffer->buffer.resource.client = resource->client;
buffer->buffer.resource.destroy = destroy_buffer;
- return buffer;
+ wl_client_add_resource(client, &buffer->buffer.resource);
}
static void
-shm_create_buffer(struct wl_client *client, struct wl_resource *resource,
- uint32_t id, int fd, int32_t width, int32_t height,
- int32_t stride, uint32_t format)
+destroy_pool(struct wl_resource *resource)
{
- struct wl_shm_buffer *buffer;
- void *data;
+ struct wl_shm_pool *pool = resource->data;
+ shm_pool_unref(pool);
+}
- switch (format) {
- case WL_SHM_FORMAT_ARGB8888:
- case WL_SHM_FORMAT_XRGB8888:
- break;
- default:
- wl_resource_post_error(resource,
- WL_SHM_ERROR_INVALID_FORMAT,
- "invalid format");
+static void
+shm_pool_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource, 0);
+}
+
+struct wl_shm_pool_interface shm_pool_interface = {
+ shm_pool_create_buffer,
+ shm_pool_destroy
+};
+
+static void
+shm_create_pool(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id, int fd, int32_t size)
+{
+ struct wl_shm_pool *pool;
+
+ pool = malloc(sizeof *pool);
+ if (pool == NULL) {
+ wl_resource_post_no_memory(resource);
close(fd);
return;
}
- if (width < 0 || height < 0 || stride < width) {
+ if (size <= 0) {
wl_resource_post_error(resource,
WL_SHM_ERROR_INVALID_STRIDE,
- "invalid width, height or stride (%dx%d, %u)",
- width, height, stride);
+ "invalid size (%d)", size);
close(fd);
return;
}
- data = mmap(NULL, stride * height,
- PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-
+ pool->refcount = 1;
+ pool->size = size;
+ pool->data = mmap(NULL, size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
- if (data == MAP_FAILED) {
+ if (pool->data == MAP_FAILED) {
wl_resource_post_error(resource,
WL_SHM_ERROR_INVALID_FD,
"failed mmap fd %d", fd);
return;
}
- buffer = wl_shm_buffer_init(client, id,
- width, height, stride, format, data);
- if (buffer == NULL) {
- munmap(data, stride * height);
- wl_resource_post_no_memory(resource);
- return;
- }
+ pool->resource.object.id = id;
+ pool->resource.object.interface = &wl_shm_pool_interface;
+ pool->resource.object.implementation =
+ (void (**)(void)) &shm_pool_interface;
- wl_client_add_resource(client, &buffer->buffer.resource);
+ pool->resource.data = pool;
+ pool->resource.client = client;
+ pool->resource.destroy = destroy_pool;
+
+ wl_client_add_resource(client, &pool->resource);
}
static const struct wl_shm_interface shm_interface = {
- shm_create_buffer
+ shm_create_pool
};
static void