window: use only one shm pool for all the cursor images
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.
This commit is contained in:
parent
e5a0120757
commit
001de54ea1
205
clients/window.c
205
clients/window.c
@ -66,6 +66,7 @@
|
|||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
struct cursor;
|
struct cursor;
|
||||||
|
struct shm_pool;
|
||||||
|
|
||||||
struct display {
|
struct display {
|
||||||
struct wl_display *display;
|
struct wl_display *display;
|
||||||
@ -95,6 +96,7 @@ struct display {
|
|||||||
int frame_radius;
|
int frame_radius;
|
||||||
struct xkb_desc *xkb;
|
struct xkb_desc *xkb;
|
||||||
struct cursor *cursors;
|
struct cursor *cursors;
|
||||||
|
struct shm_pool *cursor_shm_pool;
|
||||||
|
|
||||||
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
|
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
|
||||||
PFNEGLCREATEIMAGEKHRPROC create_image;
|
PFNEGLCREATEIMAGEKHRPROC create_image;
|
||||||
@ -138,9 +140,7 @@ struct window {
|
|||||||
|
|
||||||
cairo_surface_t *cairo_surface;
|
cairo_surface_t *cairo_surface;
|
||||||
|
|
||||||
struct wl_shm_pool *pool;
|
struct shm_pool *pool;
|
||||||
size_t pool_size;
|
|
||||||
void *pool_data;
|
|
||||||
|
|
||||||
window_key_handler_t key_handler;
|
window_key_handler_t key_handler;
|
||||||
window_keyboard_focus_handler_t keyboard_focus_handler;
|
window_keyboard_focus_handler_t keyboard_focus_handler;
|
||||||
@ -231,6 +231,13 @@ struct cursor {
|
|||||||
struct cursor_image *images;
|
struct cursor_image *images;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct shm_pool {
|
||||||
|
struct wl_shm_pool *pool;
|
||||||
|
size_t size;
|
||||||
|
size_t used;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
POINTER_DEFAULT = 100,
|
POINTER_DEFAULT = 100,
|
||||||
POINTER_UNSET
|
POINTER_UNSET
|
||||||
@ -346,18 +353,20 @@ display_get_buffer_for_surface(struct display *display,
|
|||||||
|
|
||||||
struct shm_surface_data {
|
struct shm_surface_data {
|
||||||
struct surface_data data;
|
struct surface_data data;
|
||||||
void *map;
|
struct shm_pool *pool;
|
||||||
size_t length;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
shm_pool_destroy(struct shm_pool *pool);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
shm_surface_data_destroy(void *p)
|
shm_surface_data_destroy(void *p)
|
||||||
{
|
{
|
||||||
struct shm_surface_data *data = p;
|
struct shm_surface_data *data = p;
|
||||||
|
|
||||||
wl_buffer_destroy(data->data.buffer);
|
wl_buffer_destroy(data->data.buffer);
|
||||||
if (data->map)
|
if (data->pool)
|
||||||
munmap(data->map, data->length);
|
shm_pool_destroy(data->pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -402,17 +411,74 @@ make_shm_pool(struct display *display, int size, void **data)
|
|||||||
return pool;
|
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 *
|
static cairo_surface_t *
|
||||||
display_create_shm_surface(struct display *display,
|
display_create_shm_surface_from_pool(struct display *display,
|
||||||
struct rectangle *rectangle, uint32_t flags,
|
struct rectangle *rectangle,
|
||||||
struct window *window)
|
uint32_t flags, struct shm_pool *pool)
|
||||||
{
|
{
|
||||||
struct shm_surface_data *data;
|
struct shm_surface_data *data;
|
||||||
struct wl_shm_pool *pool = NULL;
|
|
||||||
uint32_t format;
|
uint32_t format;
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
|
int stride, length, offset;
|
||||||
void *map;
|
void *map;
|
||||||
int stride;
|
|
||||||
|
|
||||||
data = malloc(sizeof *data);
|
data = malloc(sizeof *data);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
@ -420,14 +486,13 @@ display_create_shm_surface(struct display *display,
|
|||||||
|
|
||||||
stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
|
stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
|
||||||
rectangle->width);
|
rectangle->width);
|
||||||
data->length = stride * rectangle->height;
|
length = stride * rectangle->height;
|
||||||
if (window && window->pool && data->length < window->pool_size) {
|
data->pool = NULL;
|
||||||
pool = window->pool;
|
map = shm_pool_allocate(pool, length, &offset);
|
||||||
map = window->pool_data;
|
|
||||||
data->map = NULL;
|
if (!map) {
|
||||||
} else {
|
free(data);
|
||||||
pool = make_shm_pool(display, data->length, &map);
|
return NULL;
|
||||||
data->map = map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
surface = cairo_image_surface_create_for_data (map,
|
surface = cairo_image_surface_create_for_data (map,
|
||||||
@ -444,13 +509,50 @@ display_create_shm_surface(struct display *display,
|
|||||||
else
|
else
|
||||||
format = WL_SHM_FORMAT_ARGB8888;
|
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->width,
|
||||||
rectangle->height,
|
rectangle->height,
|
||||||
stride, format);
|
stride, format);
|
||||||
|
|
||||||
if (data->map)
|
return surface;
|
||||||
wl_shm_pool_destroy(pool);
|
}
|
||||||
|
|
||||||
|
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;
|
return surface;
|
||||||
}
|
}
|
||||||
@ -517,7 +619,8 @@ create_cursor_from_images(struct display *display, struct cursor *cursor,
|
|||||||
rect.height = image->height;
|
rect.height = image->height;
|
||||||
|
|
||||||
cursor->images[i].surface =
|
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,
|
shm_surface_write(cursor->images[i].surface,
|
||||||
(unsigned char *) image->pixels,
|
(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
|
static void
|
||||||
create_cursors(struct display *display)
|
create_cursors(struct display *display)
|
||||||
{
|
{
|
||||||
int i, count;
|
int i, count;
|
||||||
|
size_t pool_size = 0;
|
||||||
struct cursor *cursor;
|
struct cursor *cursor;
|
||||||
XcursorImages *images;
|
XcursorImages **images;
|
||||||
|
|
||||||
count = ARRAY_LENGTH(cursors);
|
count = ARRAY_LENGTH(cursors);
|
||||||
display->cursors = malloc(count * sizeof *display->cursors);
|
display->cursors = malloc(count * sizeof *display->cursors);
|
||||||
for (i = 0; i < count; i++) {
|
images = malloc(count * sizeof images[0]);
|
||||||
images = XcursorLibraryLoadImages(cursors[i], NULL, 32);
|
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
images[i] = XcursorLibraryLoadImages(cursors[i], NULL, 32);
|
||||||
if (!images) {
|
if (!images) {
|
||||||
fprintf(stderr, "Error loading cursor: %s\n",
|
fprintf(stderr, "Error loading cursor: %s\n",
|
||||||
cursors[i]);
|
cursors[i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
pool_size += data_length_for_cursor_images(images[i]);
|
||||||
cursor = &display->cursors[i];
|
|
||||||
create_cursor_from_images(display, cursor, images);
|
|
||||||
|
|
||||||
XcursorImagesDestroy(images);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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[i]);
|
||||||
|
|
||||||
|
XcursorImagesDestroy(images[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(images);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -579,7 +709,9 @@ destroy_cursors(struct display *display)
|
|||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
destroy_cursor_images(&display->cursors[i]);
|
destroy_cursor_images(&display->cursors[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(display->cursors);
|
free(display->cursors);
|
||||||
|
shm_pool_destroy(display->cursor_shm_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_surface_t *
|
cairo_surface_t *
|
||||||
@ -1258,10 +1390,8 @@ frame_button_handler(struct widget *widget,
|
|||||||
pool to create buffers out of while
|
pool to create buffers out of while
|
||||||
we resize. We should probably base
|
we resize. We should probably base
|
||||||
this number on the size of the output. */
|
this number on the size of the output. */
|
||||||
window->pool_size = 6 * 1024 * 1024;
|
window->pool =
|
||||||
window->pool = make_shm_pool(display,
|
shm_pool_create(display, 6 * 1024 * 1024);
|
||||||
window->pool_size,
|
|
||||||
&window->pool_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_shell_surface_resize(window->shell_surface,
|
wl_shell_surface_resize(window->shell_surface,
|
||||||
@ -1486,8 +1616,7 @@ input_handle_pointer_enter(void *data,
|
|||||||
window = input->pointer_focus;
|
window = input->pointer_focus;
|
||||||
|
|
||||||
if (window->pool) {
|
if (window->pool) {
|
||||||
wl_shm_pool_destroy(window->pool);
|
shm_pool_destroy(window->pool);
|
||||||
munmap(window->pool_data, window->pool_size);
|
|
||||||
window->pool = NULL;
|
window->pool = NULL;
|
||||||
/* Schedule a redraw to free the pool */
|
/* Schedule a redraw to free the pool */
|
||||||
window_schedule_redraw(window);
|
window_schedule_redraw(window);
|
||||||
|
Loading…
Reference in New Issue
Block a user