window: convert shm path to toysurface

Implement shm_surface as a sub-class of toysurface, and unify the
toysurface call sites removing most buffer type specific branching.

Do not destroy and create a surface, if the size does not change.

The resizing optimization of shm surfaces is retained, but the pool is
moved from struct window to struct shm_surface, since it does not apply
to egl_window_surface.

Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
dev
Pekka Paalanen 12 years ago committed by Kristian Høgsberg
parent 03fc316000
commit 9943686be3
  1. 252
      clients/window.c

@ -1,5 +1,6 @@
/* /*
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* Copyright © 2012 Collabora, Ltd.
* *
* Permission to use, copy, modify, distribute, and sell this software and its * Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that * documentation for any purpose is hereby granted without fee, provided that
@ -148,10 +149,11 @@ struct toysurface {
* of the right size available for rendering, and returns it. * of the right size available for rendering, and returns it.
* dx,dy are the x,y of wl_surface.attach. * dx,dy are the x,y of wl_surface.attach.
* width,height are the new surface size. * width,height are the new surface size.
* If resize_hint is non-zero, the user is doing continuous resizing.
* Returns the Cairo surface to draw to. * Returns the Cairo surface to draw to.
*/ */
cairo_surface_t *(*prepare)(struct toysurface *base, int dx, int dy, cairo_surface_t *(*prepare)(struct toysurface *base, int dx, int dy,
int width, int height); int width, int height, int resize_hint);
/* /*
* Post the surface to the server, returning the server allocation * Post the surface to the server, returning the server allocation
@ -203,11 +205,10 @@ struct window {
int focus_count; int focus_count;
enum window_buffer_type buffer_type; enum window_buffer_type buffer_type;
struct toysurface *toysurface; struct toysurface *toysurface;
cairo_surface_t *cairo_surface; cairo_surface_t *cairo_surface;
struct shm_pool *pool; int resizing;
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;
@ -406,7 +407,7 @@ to_egl_window_surface(struct toysurface *base)
static cairo_surface_t * static cairo_surface_t *
egl_window_surface_prepare(struct toysurface *base, int dx, int dy, egl_window_surface_prepare(struct toysurface *base, int dx, int dy,
int width, int height) int width, int height, int resize_hint)
{ {
struct egl_window_surface *surface = to_egl_window_surface(base); struct egl_window_surface *surface = to_egl_window_surface(base);
@ -693,20 +694,24 @@ display_create_shm_surface_from_pool(struct display *display,
static cairo_surface_t * static cairo_surface_t *
display_create_shm_surface(struct display *display, display_create_shm_surface(struct display *display,
struct rectangle *rectangle, uint32_t flags, struct rectangle *rectangle, uint32_t flags,
struct window *window) struct shm_pool *alternate_pool,
struct shm_surface_data **data_ret)
{ {
struct shm_surface_data *data; struct shm_surface_data *data;
struct shm_pool *pool; struct shm_pool *pool;
cairo_surface_t *surface; cairo_surface_t *surface;
if (window && window->pool) { if (alternate_pool) {
shm_pool_reset(window->pool); shm_pool_reset(alternate_pool);
surface = display_create_shm_surface_from_pool(display, surface = display_create_shm_surface_from_pool(display,
rectangle, rectangle,
flags, flags,
window->pool); alternate_pool);
if (surface) if (surface) {
return surface; data = cairo_surface_get_user_data(surface,
&shm_surface_data_key);
goto out;
}
} }
pool = shm_pool_create(display, pool = shm_pool_create(display,
@ -727,6 +732,10 @@ display_create_shm_surface(struct display *display,
data = cairo_surface_get_user_data(surface, &shm_surface_data_key); data = cairo_surface_get_user_data(surface, &shm_surface_data_key);
data->pool = pool; data->pool = pool;
out:
if (data_ret)
*data_ret = data;
return surface; return surface;
} }
@ -751,7 +760,147 @@ display_create_surface(struct display *display,
return NULL; return NULL;
assert(flags & SURFACE_SHM); assert(flags & SURFACE_SHM);
return display_create_shm_surface(display, rectangle, flags, NULL); return display_create_shm_surface(display, rectangle, flags,
NULL, NULL);
}
struct shm_surface {
struct toysurface base;
struct display *display;
struct wl_surface *surface;
uint32_t flags;
int dx, dy;
cairo_surface_t *cairo_surface;
/* 'data' is automatically destroyed, when 'cairo_surface' is */
struct shm_surface_data *data;
struct shm_pool *resize_pool;
};
static struct shm_surface *
to_shm_surface(struct toysurface *base)
{
return container_of(base, struct shm_surface, base);
}
static cairo_surface_t *
shm_surface_prepare(struct toysurface *base, int dx, int dy,
int width, int height, int resize_hint)
{
struct shm_surface *surface = to_shm_surface(base);
struct rectangle rect = { 0, 0, width, height };
surface->dx = dx;
surface->dy = dy;
if (!resize_hint && surface->resize_pool) {
cairo_surface_destroy(surface->cairo_surface);
shm_pool_destroy(surface->resize_pool);
surface->resize_pool = NULL;
surface->cairo_surface = NULL;
}
if (surface->cairo_surface &&
cairo_image_surface_get_width(surface->cairo_surface) == width &&
cairo_image_surface_get_height(surface->cairo_surface) == height)
goto out;
if (surface->cairo_surface)
cairo_surface_destroy(surface->cairo_surface);
if (resize_hint && !surface->resize_pool) {
/* Create a big pool to allocate from, while continuously
* resizing. Mmapping a new pool in the server
* is relatively expensive, so reusing a pool performs
* better, but may temporarily reserve unneeded memory.
*/
/* We should probably base this number on the output size. */
surface->resize_pool = shm_pool_create(surface->display,
6 * 1024 * 1024);
}
surface->cairo_surface =
display_create_shm_surface(surface->display, &rect,
surface->flags,
surface->resize_pool,
&surface->data);
out:
return cairo_surface_reference(surface->cairo_surface);
}
static void
shm_surface_swap(struct toysurface *base,
struct rectangle *server_allocation)
{
struct shm_surface *surface = to_shm_surface(base);
server_allocation->width =
cairo_image_surface_get_width(surface->cairo_surface);
server_allocation->height =
cairo_image_surface_get_height(surface->cairo_surface);
wl_surface_attach(surface->surface, surface->data->buffer,
surface->dx, surface->dy);
wl_surface_damage(surface->surface, 0, 0,
server_allocation->width, server_allocation->height);
wl_surface_commit(surface->surface);
}
static int
shm_surface_acquire(struct toysurface *base, EGLContext ctx)
{
return -1;
}
static void
shm_surface_release(struct toysurface *base)
{
}
static void
shm_surface_destroy(struct toysurface *base)
{
struct shm_surface *surface = to_shm_surface(base);
/* this destroys surface->data, too */
cairo_surface_destroy(surface->cairo_surface);
if (surface->resize_pool)
shm_pool_destroy(surface->resize_pool);
free(surface);
}
static struct toysurface *
shm_surface_create(struct display *display, struct wl_surface *wl_surface,
uint32_t flags, struct rectangle *rectangle)
{
struct shm_surface *surface;
surface = calloc(1, sizeof *surface);
if (!surface)
return NULL;
surface->base.prepare = shm_surface_prepare;
surface->base.swap = shm_surface_swap;
surface->base.acquire = shm_surface_acquire;
surface->base.release = shm_surface_release;
surface->base.destroy = shm_surface_destroy;
surface->display = display;
surface->surface = wl_surface;
surface->flags = flags;
surface->cairo_surface = display_create_shm_surface(display, rectangle,
flags, NULL,
&surface->data);
if (!surface->cairo_surface) {
free(surface);
return NULL;
}
return &surface->base;
} }
/* /*
@ -924,8 +1073,6 @@ static void
window_attach_surface(struct window *window) window_attach_surface(struct window *window)
{ {
struct display *display = window->display; struct display *display = window->display;
struct wl_buffer *buffer;
int32_t x, y;
if (window->type == TYPE_NONE) { if (window->type == TYPE_NONE) {
window->type = TYPE_TOPLEVEL; window->type = TYPE_TOPLEVEL;
@ -947,29 +1094,8 @@ window_attach_surface(struct window *window)
window->input_region = NULL; window->input_region = NULL;
} }
switch (window->buffer_type) {
#ifdef HAVE_CAIRO_EGL
case WINDOW_BUFFER_TYPE_EGL_WINDOW:
window->toysurface->swap(window->toysurface, window->toysurface->swap(window->toysurface,
&window->server_allocation); &window->server_allocation);
break;
#endif
case WINDOW_BUFFER_TYPE_SHM:
buffer =
display_get_buffer_for_surface(display,
window->cairo_surface);
window_get_resize_dx_dy(window, &x, &y);
wl_surface_attach(window->surface, buffer, x, y);
wl_surface_damage(window->surface, 0, 0,
window->allocation.width,
window->allocation.height);
wl_surface_commit(window->surface);
window->server_allocation = window->allocation;
break;
default:
return;
}
} }
int int
@ -989,17 +1115,6 @@ window_flush(struct window *window)
window->cairo_surface = NULL; window->cairo_surface = NULL;
} }
static void
window_set_surface(struct window *window, cairo_surface_t *surface)
{
cairo_surface_reference(surface);
if (window->cairo_surface != NULL)
cairo_surface_destroy(window->cairo_surface);
window->cairo_surface = surface;
}
struct display * struct display *
window_get_display(struct window *window) window_get_display(struct window *window)
{ {
@ -1009,8 +1124,8 @@ window_get_display(struct window *window)
static void static void
window_create_surface(struct window *window) window_create_surface(struct window *window)
{ {
cairo_surface_t *surface;
uint32_t flags = 0; uint32_t flags = 0;
int dx, dy;
if (!window->transparent) if (!window->transparent)
flags = SURFACE_OPAQUE; flags = SURFACE_OPAQUE;
@ -1025,30 +1140,25 @@ window_create_surface(struct window *window)
flags, flags,
&window->allocation); &window->allocation);
if (window->toysurface) { if (window->toysurface)
int dx, dy;
window_get_resize_dx_dy(window, &dx, &dy);
surface = window->toysurface->prepare(window->toysurface,
dx, dy,
window->allocation.width,
window->allocation.height);
break; break;
}
/* fall through */ /* fall through */
#endif #endif
case WINDOW_BUFFER_TYPE_SHM: case WINDOW_BUFFER_TYPE_SHM:
surface = display_create_shm_surface(window->display, window->toysurface = shm_surface_create(window->display,
&window->allocation, window->surface, flags,
flags, window); &window->allocation);
break; break;
default: default:
surface = NULL; assert(0);
break;
} }
window_set_surface(window, surface); window_get_resize_dx_dy(window, &dx, &dy);
cairo_surface_destroy(surface); window->cairo_surface =
window->toysurface->prepare(window->toysurface, dx, dy,
window->allocation.width,
window->allocation.height,
window->resizing);
} }
static void frame_destroy(struct frame *frame); static void frame_destroy(struct frame *frame);
@ -1092,9 +1202,6 @@ window_destroy(struct window *window)
wl_surface_destroy(window->surface); wl_surface_destroy(window->surface);
wl_list_remove(&window->link); wl_list_remove(&window->link);
if (window->cairo_surface != NULL)
cairo_surface_destroy(window->cairo_surface);
if (window->toysurface) if (window->toysurface)
window->toysurface->destroy(window->toysurface); window->toysurface->destroy(window->toysurface);
@ -1958,15 +2065,7 @@ frame_button_handler(struct widget *widget,
break; break;
input_ungrab(input); input_ungrab(input);
if (!display->dpy) { window->resizing = 1;
/* 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 =
shm_pool_create(display, 6 * 1024 * 1024);
}
wl_shell_surface_resize(window->shell_surface, wl_shell_surface_resize(window->shell_surface,
input_get_seat(input), input_get_seat(input),
display->serial, location); display->serial, location);
@ -2140,9 +2239,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
input->pointer_focus = wl_surface_get_user_data(surface); input->pointer_focus = wl_surface_get_user_data(surface);
window = input->pointer_focus; window = input->pointer_focus;
if (window->pool) { if (window->resizing) {
shm_pool_destroy(window->pool); window->resizing = 0;
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…
Cancel
Save