[PATCH] window: use only one shm pool for all the cursor images
Kristian Høgsberg
krh at bitplanet.net
Mon May 7 11:45:26 PDT 2012
On Mon, May 7, 2012 at 2:34 PM, Ander Conselvan de Oliveira
<conselvan2 at gmail.com> wrote:
> Cursor images are fairly small and having one pool for each image adds
> a lot of unnecessary overhead. Instead, create one large pool and
> allocated all cursor images from that.
>
> In order to do that, however, the code that creates shm surface needed
> some refactoring. This patch adds a new struct shm_pool that is used
> by the cursor and also changes struct window to use it.
Very nice, committed.
Kristian
> ---
> clients/window.c | 199 ++++++++++++++++++++++++++++++++++++++++++++----------
> 1 file changed, 164 insertions(+), 35 deletions(-)
>
> diff --git a/clients/window.c b/clients/window.c
> index 2dcf421..531cedc 100644
> --- a/clients/window.c
> +++ b/clients/window.c
> @@ -66,6 +66,7 @@
> #include "window.h"
>
> struct cursor;
> +struct shm_pool;
>
> struct display {
> struct wl_display *display;
> @@ -95,6 +96,7 @@ struct display {
> int frame_radius;
> struct xkb_desc *xkb;
> struct cursor *cursors;
> + struct shm_pool *cursor_shm_pool;
>
> PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
> PFNEGLCREATEIMAGEKHRPROC create_image;
> @@ -138,9 +140,7 @@ struct window {
>
> cairo_surface_t *cairo_surface;
>
> - struct wl_shm_pool *pool;
> - size_t pool_size;
> - void *pool_data;
> + struct shm_pool *pool;
>
> window_key_handler_t key_handler;
> window_keyboard_focus_handler_t keyboard_focus_handler;
> @@ -231,6 +231,13 @@ struct cursor {
> struct cursor_image *images;
> };
>
> +struct shm_pool {
> + struct wl_shm_pool *pool;
> + size_t size;
> + size_t used;
> + void *data;
> +};
> +
> enum {
> POINTER_DEFAULT = 100,
> POINTER_UNSET
> @@ -346,18 +353,20 @@ display_get_buffer_for_surface(struct display *display,
>
> struct shm_surface_data {
> struct surface_data data;
> - void *map;
> - size_t length;
> + struct shm_pool *pool;
> };
>
> static void
> +shm_pool_destroy(struct shm_pool *pool);
> +
> +static void
> shm_surface_data_destroy(void *p)
> {
> struct shm_surface_data *data = p;
>
> wl_buffer_destroy(data->data.buffer);
> - if (data->map)
> - munmap(data->map, data->length);
> + if (data->pool)
> + shm_pool_destroy(data->pool);
> }
>
> static void
> @@ -402,17 +411,74 @@ make_shm_pool(struct display *display, int size, void **data)
> return pool;
> }
>
> +static struct shm_pool *
> +shm_pool_create(struct display *display, size_t size)
> +{
> + struct shm_pool *pool = malloc(sizeof *pool);
> +
> + if (!pool)
> + return NULL;
> +
> + pool->pool = make_shm_pool(display, size, &pool->data);
> + if (!pool->pool) {
> + free(pool);
> + return NULL;
> + }
> +
> + pool->size = size;
> + pool->used = 0;
> +
> + return pool;
> +}
> +
> +static void *
> +shm_pool_allocate(struct shm_pool *pool, size_t size, int *offset)
> +{
> + if (pool->used + size > pool->size)
> + return NULL;
> +
> + *offset = pool->used;
> + pool->used += size;
> +
> + return (char *) pool->data + *offset;
> +}
> +
> +/* destroy the pool. this does not unmap the memory though */
> +static void
> +shm_pool_destroy(struct shm_pool *pool)
> +{
> + munmap(pool->data, pool->size);
> + wl_shm_pool_destroy(pool->pool);
> + free(pool);
> +}
> +
> +/* Start allocating from the beginning of the pool again */
> +static void
> +shm_pool_reset(struct shm_pool *pool)
> +{
> + pool->used = 0;
> +}
> +
> +static int
> +data_length_for_shm_surface(struct rectangle *rect)
> +{
> + int stride;
> +
> + stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
> + rect->width);
> + return stride * rect->height;
> +}
> +
> static cairo_surface_t *
> -display_create_shm_surface(struct display *display,
> - struct rectangle *rectangle, uint32_t flags,
> - struct window *window)
> +display_create_shm_surface_from_pool(struct display *display,
> + struct rectangle *rectangle,
> + uint32_t flags, struct shm_pool *pool)
> {
> struct shm_surface_data *data;
> - struct wl_shm_pool *pool = NULL;
> uint32_t format;
> cairo_surface_t *surface;
> + int stride, length, offset;
> void *map;
> - int stride;
>
> data = malloc(sizeof *data);
> if (data == NULL)
> @@ -420,14 +486,13 @@ display_create_shm_surface(struct display *display,
>
> stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
> rectangle->width);
> - data->length = stride * rectangle->height;
> - if (window && window->pool && data->length < window->pool_size) {
> - pool = window->pool;
> - map = window->pool_data;
> - data->map = NULL;
> - } else {
> - pool = make_shm_pool(display, data->length, &map);
> - data->map = map;
> + length = stride * rectangle->height;
> + data->pool = NULL;
> + map = shm_pool_allocate(pool, length, &offset);
> +
> + if (!map) {
> + free(data);
> + return NULL;
> }
>
> surface = cairo_image_surface_create_for_data (map,
> @@ -444,13 +509,50 @@ display_create_shm_surface(struct display *display,
> else
> format = WL_SHM_FORMAT_ARGB8888;
>
> - data->data.buffer = wl_shm_pool_create_buffer(pool, 0,
> + data->data.buffer = wl_shm_pool_create_buffer(pool->pool, offset,
> rectangle->width,
> rectangle->height,
> stride, format);
>
> - if (data->map)
> - wl_shm_pool_destroy(pool);
> + return surface;
> +}
> +
> +static cairo_surface_t *
> +display_create_shm_surface(struct display *display,
> + struct rectangle *rectangle, uint32_t flags,
> + struct window *window)
> +{
> + struct shm_surface_data *data;
> + struct shm_pool *pool;
> + cairo_surface_t *surface;
> +
> + if (window && window->pool) {
> + shm_pool_reset(window->pool);
> + surface = display_create_shm_surface_from_pool(display,
> + rectangle,
> + flags,
> + window->pool);
> + if (surface)
> + return surface;
> + }
> +
> + pool = shm_pool_create(display,
> + data_length_for_shm_surface(rectangle));
> + if (!pool)
> + return NULL;
> +
> + surface =
> + display_create_shm_surface_from_pool(display, rectangle,
> + flags, pool);
> +
> + if (!surface) {
> + shm_pool_destroy(pool);
> + return NULL;
> + }
> +
> + /* make sure we destroy the pool when the surface is destroyed */
> + data = cairo_surface_get_user_data(surface, &surface_data_key);
> + data->pool = pool;
>
> return surface;
> }
> @@ -517,7 +619,8 @@ create_cursor_from_images(struct display *display, struct cursor *cursor,
> rect.height = image->height;
>
> cursor->images[i].surface =
> - display_create_shm_surface(display, &rect, 0, NULL);
> + display_create_shm_surface_from_pool(display, &rect, 0,
> + display->cursor_shm_pool);
>
> shm_surface_write(cursor->images[i].surface,
> (unsigned char *) image->pixels,
> @@ -532,30 +635,57 @@ create_cursor_from_images(struct display *display, struct cursor *cursor,
>
> }
>
> +static size_t
> +data_length_for_cursor_images(XcursorImages *images)
> +{
> + int i;
> + size_t length = 0;
> + struct rectangle rect;
> +
> + for (i = 0; i < images->nimage; i++) {
> + rect.width = images->images[i]->width;
> + rect.height = images->images[i]->height;
> + length += data_length_for_shm_surface(&rect);
> + }
> +
> + return length;
> +}
> +
> static void
> create_cursors(struct display *display)
> {
> int i, count;
> + size_t pool_size = 0;
> struct cursor *cursor;
> - XcursorImages *images;
> + XcursorImages **images;
>
> count = ARRAY_LENGTH(cursors);
> display->cursors = malloc(count * sizeof *display->cursors);
> - for (i = 0; i < count; i++) {
> - images = XcursorLibraryLoadImages(cursors[i], NULL, 32);
> + images = malloc(count * sizeof images[0]);
>
> + for (i = 0; i < count; i++) {
> + images[i] = XcursorLibraryLoadImages(cursors[i], NULL, 32);
> if (!images) {
> fprintf(stderr, "Error loading cursor: %s\n",
> cursors[i]);
> continue;
> }
> + pool_size += data_length_for_cursor_images(images[i]);
> + }
> +
> + display->cursor_shm_pool = shm_pool_create(display, pool_size);
> +
> + for (i = 0; i < count; i++) {
> + if (!images)
> + continue;
>
> cursor = &display->cursors[i];
> - create_cursor_from_images(display, cursor, images);
> + create_cursor_from_images(display, cursor, images[i]);
>
> - XcursorImagesDestroy(images);
> + XcursorImagesDestroy(images[i]);
> }
>
> + free(images);
> }
>
> static void
> @@ -579,7 +709,9 @@ destroy_cursors(struct display *display)
> for (i = 0; i < count; ++i) {
> destroy_cursor_images(&display->cursors[i]);
> }
> +
> free(display->cursors);
> + shm_pool_destroy(display->cursor_shm_pool);
> }
>
> cairo_surface_t *
> @@ -1258,10 +1390,8 @@ frame_button_handler(struct widget *widget,
> pool to create buffers out of while
> we resize. We should probably base
> this number on the size of the output. */
> - window->pool_size = 6 * 1024 * 1024;
> - window->pool = make_shm_pool(display,
> - window->pool_size,
> - &window->pool_data);
> + window->pool =
> + shm_pool_create(display, 6 * 1024 * 1024);
> }
>
> wl_shell_surface_resize(window->shell_surface,
> @@ -1486,8 +1616,7 @@ input_handle_pointer_enter(void *data,
> window = input->pointer_focus;
>
> if (window->pool) {
> - wl_shm_pool_destroy(window->pool);
> - munmap(window->pool_data, window->pool_size);
> + shm_pool_destroy(window->pool);
> window->pool = NULL;
> /* Schedule a redraw to free the pool */
> window_schedule_redraw(window);
> --
> 1.7.9.5
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
More information about the wayland-devel
mailing list