window: Use a persistent, big shm pool during resize
authorKristian Høgsberg <krh@bitplanet.net>
Tue, 3 Apr 2012 16:00:48 +0000 (12:00 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Tue, 3 Apr 2012 16:00:48 +0000 (12:00 -0400)
The biggest performance bottleneck while resizing is the continous
setting up and tearing down of mmaps and faulting in pages.  This commit
introduces a per-window pool that we'll allocate buffers out of if it's
available.  Then we set initialize it to a big shm pool when we start
resizing and free it when resizing is done.

clients/window.c

index de69003..73b7e88 100644 (file)
@@ -133,6 +133,10 @@ struct window {
 
        cairo_surface_t *cairo_surface, *pending_surface;
 
+       struct wl_shm_pool *pool;
+       size_t pool_size;
+       void *pool_data;
+
        window_key_handler_t key_handler;
        window_keyboard_focus_handler_t keyboard_focus_handler;
        window_data_handler_t data_handler;
@@ -497,12 +501,14 @@ make_shm_pool(struct display *display, int size, void **data)
 
 static cairo_surface_t *
 display_create_shm_surface(struct display *display,
-                          struct rectangle *rectangle, uint32_t flags)
+                          struct rectangle *rectangle, uint32_t flags,
+                          struct window *window)
 {
        struct shm_surface_data *data;
-       struct wl_shm_pool *pool;
+       struct wl_shm_pool *pool = NULL;
        uint32_t format;
        cairo_surface_t *surface;
+       void *map;
        int stride;
 
        data = malloc(sizeof *data);
@@ -512,9 +518,15 @@ display_create_shm_surface(struct display *display,
        stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
                                                rectangle->width);
        data->length = stride * rectangle->height;
-       pool = make_shm_pool(display, data->length, &data->map);
+       if (window && window->pool && data->length < window->pool_size) {
+               pool = window->pool;
+               map = window->pool_data;
+       } else {
+               pool = make_shm_pool(display, data->length, &data->map);
+               map = data->map;
+       }
 
-       surface = cairo_image_surface_create_for_data (data->map,
+       surface = cairo_image_surface_create_for_data (map,
                                                       CAIRO_FORMAT_ARGB32,
                                                       rectangle->width,
                                                       rectangle->height,
@@ -533,7 +545,8 @@ display_create_shm_surface(struct display *display,
                                                      rectangle->height,
                                                      stride, format);
 
-       wl_shm_pool_destroy(pool);
+       if (map == data->map)
+               wl_shm_pool_destroy(pool);
 
        return surface;
 }
@@ -550,7 +563,7 @@ display_create_shm_surface_from_file(struct display *display,
 
        image = load_image(filename);
 
-       surface = display_create_shm_surface(display, rect, 0);
+       surface = display_create_shm_surface(display, rect, 0, NULL);
        if (surface == NULL) {
                pixman_image_unref(image);
                return NULL;
@@ -597,7 +610,7 @@ display_create_surface(struct display *display,
                                                                rectangle);
        }
 #endif
-       return display_create_shm_surface(display, rectangle, flags);
+       return display_create_shm_surface(display, rectangle, flags, NULL);
 }
 
 static cairo_surface_t *
@@ -867,7 +880,8 @@ window_create_surface(struct window *window)
 #endif
        case WINDOW_BUFFER_TYPE_SHM:
                surface = display_create_shm_surface(window->display,
-                                                    &window->allocation, flags);
+                                                    &window->allocation,
+                                                    flags, window);
                break;
         default:
                surface = NULL;
@@ -1345,7 +1359,9 @@ frame_button_handler(struct widget *widget,
 {
        struct frame *frame = data;
        struct window *window = widget->window;
+       struct display *display = window->display;
        int location;
+
        location = frame_get_pointer_location(frame, input->sx, input->sy);
 
        if (window->display->shell && button == BTN_LEFT && state == 1) {
@@ -1370,6 +1386,18 @@ frame_button_handler(struct widget *widget,
                        if (!window->shell_surface)
                                break;
                        input_ungrab(input, time);
+
+                       if (!display->dpy) {
+                               /* If we're using shm, allocate a big
+                                  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);
+                       }
+
                        wl_shell_surface_resize(window->shell_surface,
                                                input_get_input_device(input),
                                                time, location);
@@ -1588,6 +1616,14 @@ input_handle_pointer_enter(void *data,
        input->pointer_focus = wl_surface_get_user_data(surface);
        window = input->pointer_focus;
 
+       if (window->pool) {
+               wl_shm_pool_destroy(window->pool);
+               munmap(window->pool_data, window->pool_size);
+               window->pool = NULL;
+               /* Schedule a redraw to free the pool */
+               window_schedule_redraw(window);
+       }
+
        input->sx = sx;
        input->sy = sy;