[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